summaryrefslogtreecommitdiff
path: root/telephony
diff options
context:
space:
mode:
author Nathan Harold <nharold@google.com> 2025-01-27 08:52:28 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-01-27 08:52:28 -0800
commitdc3783b2bce0b7a0a653e51f50c5902d804ed8a5 (patch)
tree0e2555820b552355a32cf0ef021923a037a7e6bf /telephony
parentcf6222d1e679007bbf9011f0092b455b215ed106 (diff)
parentd51739e9d51d993c750f704d6f8ad2dd9f513838 (diff)
Merge "Move to a shared Worker Thread" into main
Diffstat (limited to 'telephony')
-rw-r--r--telephony/java/com/android/internal/telephony/util/WorkerThread.java130
1 files changed, 130 insertions, 0 deletions
diff --git a/telephony/java/com/android/internal/telephony/util/WorkerThread.java b/telephony/java/com/android/internal/telephony/util/WorkerThread.java
new file mode 100644
index 000000000000..f5b653656352
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/WorkerThread.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.HandlerThread;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+
+/**
+ * Shared singleton worker thread for each process.
+ *
+ * This thread should be used for work that needs to be executed at standard priority
+ * but not on the main thread. This is suitable for handling asynchronous tasks that
+ * are ephemeral or require enough work that they shouldn't block the main thread, but
+ * should not block each other for more than around 100ms.
+ */
+public final class WorkerThread extends HandlerThread {
+ private static volatile WorkerThread sInstance;
+ private static volatile Handler sHandler;
+ private static volatile HandlerExecutor sHandlerExecutor;
+ private static final Object sLock = new Object();
+
+ private CountDownLatch mInitLock = new CountDownLatch(1);
+
+
+ private WorkerThread() {
+ super("android.telephony.worker");
+ }
+
+ private static void ensureThread() {
+ if (sInstance != null) return;
+ synchronized (sLock) {
+ if (sInstance != null) return;
+
+ final WorkerThread tmpThread = new WorkerThread();
+ tmpThread.start();
+
+ try {
+ tmpThread.mInitLock.await();
+ } catch (InterruptedException ignored) {
+ }
+
+
+ sHandler = new Handler(
+ tmpThread.getLooper(),
+ /* callback= */ null,
+ /* async= */ false,
+ /* shared= */ true);
+ sHandlerExecutor = new HandlerExecutor(sHandler);
+ sInstance = tmpThread; // Note: order matters here. sInstance must be assigned last.
+
+ }
+ }
+
+ @Override
+ protected void onLooperPrepared() {
+ mInitLock.countDown();
+ }
+
+ /**
+ * Get the worker thread directly.
+ *
+ * Users of this thread should take care not to block it for extended periods of
+ * time.
+ *
+ * @return a HandlerThread, never null
+ */
+ @NonNull public static HandlerThread get() {
+ ensureThread();
+ return sInstance;
+ }
+
+ /**
+ * Get a Handler that can process Runnables.
+ *
+ * @return a Handler, never null
+ */
+ @NonNull public static Handler getHandler() {
+ ensureThread();
+ return sHandler;
+ }
+
+ /**
+ * Get an Executor that can process Runnables
+ *
+ * @return an Executor, never null
+ */
+ @NonNull public static Executor getExecutor() {
+ ensureThread();
+ return sHandlerExecutor;
+ }
+
+ /**
+ * A method to reset the WorkerThread from scratch.
+ *
+ * This method should only be used for unit testing. In production it would have
+ * catastrophic consequences. Do not ever use this outside of tests.
+ */
+ @VisibleForTesting
+ public static void reset() {
+ synchronized (sLock) {
+ if (sInstance == null) return;
+ sInstance.quitSafely();
+ sInstance = null;
+ sHandler = null;
+ sHandlerExecutor = null;
+ ensureThread();
+ }
+ }
+}