<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.react.jstasks;

import android.os.Handler;
import android.util.SparseArray;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.appregistry.AppRegistry;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Helper class for dealing with JS tasks. Handles per-ReactContext active task tracking, starting /
 * stopping tasks and notifying listeners.
 */
public class HeadlessJsTaskContext {

  private static final WeakHashMap<ReactContext, HeadlessJsTaskContext> INSTANCES =
      new WeakHashMap<>();

  /**
   * Get the task helper instance for a particular {@link ReactContext}. There is only one instance
   * per context.
   *
   * <p><strong>Note:</strong> do not hold long-lived references to the object returned here, as
   * that will cause memory leaks. Instead, just call this method on-demand.
   */
  public static HeadlessJsTaskContext getInstance(ReactContext context) {
    HeadlessJsTaskContext helper = INSTANCES.get(context);
    if (helper == null) {
      helper = new HeadlessJsTaskContext(context);
      INSTANCES.put(context, helper);
    }
    return helper;
  }

  private final WeakReference<ReactContext> mReactContext;
  private final Set<HeadlessJsTaskEventListener> mHeadlessJsTaskEventListeners =
      new CopyOnWriteArraySet<>();
  private final AtomicInteger mLastTaskId = new AtomicInteger(0);
  private final Handler mHandler = new Handler();
  private final Set<Integer> mActiveTasks = new CopyOnWriteArraySet<>();
  private final Map<Integer, HeadlessJsTaskConfig> mActiveTaskConfigs = new ConcurrentHashMap<>();
  private final SparseArray<Runnable> mTaskTimeouts = new SparseArray<>();

  private HeadlessJsTaskContext(ReactContext reactContext) {
    mReactContext = new WeakReference<ReactContext>(reactContext);
  }

  /** Register a task lifecycle event listener. */
  public void addTaskEventListener(HeadlessJsTaskEventListener listener) {
    mHeadlessJsTaskEventListeners.add(listener);
  }

  /** Unregister a task lifecycle event listener. */
  public void removeTaskEventListener(HeadlessJsTaskEventListener listener) {
    mHeadlessJsTaskEventListeners.remove(listener);
  }

  /** Get whether there are any running JS tasks at the moment. */
  public boolean hasActiveTasks() {
    return mActiveTasks.size() > 0;
  }

  /**
   * Start a JS task. Handles invoking {@link AppRegistry#startHeadlessTask} and notifying
   * listeners.
   *
   * @return a unique id representing this task instance.
   */
  public synchronized int startTask(final HeadlessJsTaskConfig taskConfig) {
    final int taskId = mLastTaskId.incrementAndGet();
    startTask(taskConfig, taskId);
    return taskId;
  }

  /**<commit_msg>fix: Android headless JS timeout (#33044)<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.react.jstasks;

import android.os.Handler;
import android.util.SparseArray;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.appregistry.AppRegistry;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Helper class for dealing with JS tasks. Handles per-ReactContext active task tracking, starting /
 * stopping tasks and notifying listeners.
 */
public class HeadlessJsTaskContext {

  private static final WeakHashMap<ReactContext, HeadlessJsTaskContext> INSTANCES =
      new WeakHashMap<>();

  /**
   * Get the task helper instance for a particular {@link ReactContext}. There is only one instance
   * per context.
   *
   * <p><strong>Note:</strong> do not hold long-lived references to the object returned here, as
   * that will cause memory leaks. Instead, just call this method on-demand.
   */
  public static HeadlessJsTaskContext getInstance(ReactContext context) {
    HeadlessJsTaskContext helper = INSTANCES.get(context);
    if (helper == null) {
      helper = new HeadlessJsTaskContext(context);
      INSTANCES.put(context, helper);
    }
    return helper;
  }

  private final WeakReference<ReactContext> mReactContext;
  private final Set<HeadlessJsTaskEventListener> mHeadlessJsTaskEventListeners =
      new CopyOnWriteArraySet<>();
  private final AtomicInteger mLastTaskId = new AtomicInteger(0);
  private final Handler mHandler = new Handler();
  private final Set<Integer> mActiveTasks = new CopyOnWriteArraySet<>();
  private final Map<Integer, HeadlessJsTaskConfig> mActiveTaskConfigs = new ConcurrentHashMap<>();
  private final SparseArray<Runnable> mTaskTimeouts = new SparseArray<>();

  private HeadlessJsTaskContext(ReactContext reactContext) {
    mReactContext = new WeakReference<ReactContext>(reactContext);
  }

  /**
   * Register a task lifecycle event listener. Synchronized in order to prevent race conditions with
   * finishTask, as the listener will be invoked for already running tasks.
   */
  public synchronized void addTaskEventListener(HeadlessJsTaskEventListener listener) {
    mHeadlessJsTaskEventListeners.add(listener);
    for (Integer activeTaskId : mActiveTasks) {
      listener.onHeadlessJsTaskStart(activeTaskId);
    }
  }

  /** Unregister a task lifecycle event listener. */
  public void removeTaskEventListener(HeadlessJsTaskEventListener listener) {
    mHeadlessJsTaskEventListeners.remove(listener);
  }

  /** Get whether there are any running JS tasks at the moment. */
  public boolean hasActiveTasks() {
    return mActiveTasks.size() > 0;
  }

  /**
   * Start a JS task. Handles invoking {@link AppRegistry#startHeadlessTask} and notifying
   * listeners.
   *
   * @return a unique id representing this task instance.
   */
  public synchronized int startTask(final HeadlessJsTaskConfig taskConfig) {
    final int taskId = mLastTaskId.incrementAndGet();
    startTask(taskConfig, taskId);
    return taskId;
  }

  /**
{'fraction_non_alphanumeric': 0.08619945315872787, 'fraction_numerical': 0.0012951503813498344, 'mean_word_length': 4.600322320709106, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4826945', 'n_tokens_mistral': 1928, 'n_tokens_neox': 1896, 'n_words': 566}