Migrate to WorkerThread and BackgroundThread
Remove a bunch of low-utilization threads from the Phone
process, instead moving standard priority work onto a new
worker thread, and background work such as metrics onto
the existing BackgroundThread.
Bug: 390244513
Flag: com.android.internal.telephony.flags.thread_shred
Test: atest FrameworksTelephonyTests
Test: manually verified CUJs on Panther
Change-Id: I4f5176921ee130a2f480575d636b2aaa9f278ff4
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index 4579ae2..4b4e02f 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -257,3 +257,14 @@
purpose: PURPOSE_BUGFIX
}
}
+#
+# OWNER=nharold TARGET=25Q4
+flag {
+ name: "thread_shred"
+ namespace: "telephony"
+ description: "Consolidate a bunch of unneeded worker threads to save resources"
+ bug:"390244513"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java
index 6326d6c..ffefce3 100644
--- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java
@@ -71,6 +71,7 @@
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.uicc.UiccPort;
import com.android.internal.telephony.uicc.UiccProfile;
+import com.android.internal.telephony.util.WorkerThread;
import com.android.telephony.Rlog;
import java.io.FileDescriptor;
@@ -369,48 +370,72 @@
if (mFeatureFlags.asyncInitCarrierPrivilegesTracker()) {
final Object localLock = new Object();
- HandlerThread initializerThread =
- new HandlerThread("CarrierPrivilegesTracker Initializer") {
- @Override
- protected void onLooperPrepared() {
- synchronized (localLock) {
- localLock.notifyAll();
- }
+ if (mFeatureFlags.threadShred()) {
+ mCurrentHandler = new Handler(WorkerThread.get().getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case ACTION_INITIALIZE_TRACKER:
+ handleInitializeTracker();
+ if (!hasMessagesOrCallbacks()) {
+ mCurrentHandler = CarrierPrivilegesTracker.this;
+ }
+ break;
+ default:
+ Message m = CarrierPrivilegesTracker.this.obtainMessage();
+ m.copyFrom(msg);
+ m.sendToTarget();
+ if (!hasMessagesOrCallbacks()) {
+ mCurrentHandler = CarrierPrivilegesTracker.this;
+ }
+ break;
}
- };
- synchronized (localLock) {
- initializerThread.start();
- while (true) {
- try {
- localLock.wait();
- break;
- } catch (InterruptedException ie) {
+ }
+ };
+ } else {
+ HandlerThread initializerThread =
+ new HandlerThread("CarrierPrivilegesTracker Initializer") {
+ @Override
+ protected void onLooperPrepared() {
+ synchronized (localLock) {
+ localLock.notifyAll();
+ }
+ }
+ };
+ synchronized (localLock) {
+ initializerThread.start();
+ while (true) {
+ try {
+ localLock.wait();
+ break;
+ } catch (InterruptedException ie) {
+ }
}
}
+ mCurrentHandler = new Handler(initializerThread.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case ACTION_INITIALIZE_TRACKER:
+ handleInitializeTracker();
+ if (!hasMessagesOrCallbacks()) {
+ mCurrentHandler = CarrierPrivilegesTracker.this;
+ initializerThread.quitSafely();
+ }
+ break;
+ default:
+ Message m = CarrierPrivilegesTracker.this.obtainMessage();
+ m.copyFrom(msg);
+ m.sendToTarget();
+ if (!hasMessagesOrCallbacks()) {
+ mCurrentHandler = CarrierPrivilegesTracker.this;
+ initializerThread.quitSafely();
+ }
+ break;
+ }
+ }
+ };
}
- mCurrentHandler = new Handler(initializerThread.getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case ACTION_INITIALIZE_TRACKER:
- handleInitializeTracker();
- if (!hasMessagesOrCallbacks()) {
- mCurrentHandler = CarrierPrivilegesTracker.this;
- initializerThread.quitSafely();
- }
- break;
- default:
- Message m = CarrierPrivilegesTracker.this.obtainMessage();
- m.copyFrom(msg);
- m.sendToTarget();
- if (!hasMessagesOrCallbacks()) {
- mCurrentHandler = CarrierPrivilegesTracker.this;
- initializerThread.quitSafely();
- }
- break;
- }
- }
- };
} else {
mCurrentHandler = this;
}
diff --git a/src/java/com/android/internal/telephony/GbaManager.java b/src/java/com/android/internal/telephony/GbaManager.java
index 047d5d5..ec194db 100644
--- a/src/java/com/android/internal/telephony/GbaManager.java
+++ b/src/java/com/android/internal/telephony/GbaManager.java
@@ -39,7 +39,9 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.metrics.RcsStats;
+import com.android.internal.telephony.util.WorkerThread;
import com.android.telephony.Rlog;
import java.util.NoSuchElementException;
@@ -66,6 +68,8 @@
public static final int REQUEST_TIMEOUT_MS = 5000;
private final RcsStats mRcsStats;
+ private final FeatureFlags mFeatureFlags;
+
private final String mLogTag;
private final Context mContext;
private final int mSubId;
@@ -202,7 +206,7 @@
@VisibleForTesting
public GbaManager(Context context, int subId, String servicePackageName, int releaseTime,
- RcsStats rcsStats) {
+ RcsStats rcsStats, Looper looper, FeatureFlags featureFlags) {
mContext = context;
mSubId = subId;
mLogTag = "GbaManager[" + subId + "]";
@@ -210,9 +214,15 @@
mServicePackageName = servicePackageName;
mReleaseTime = releaseTime;
- HandlerThread headlerThread = new HandlerThread(mLogTag);
- headlerThread.start();
- mHandler = new GbaManagerHandler(headlerThread.getLooper());
+ mFeatureFlags = featureFlags;
+
+ if (mFeatureFlags.threadShred()) {
+ mHandler = new GbaManagerHandler(looper);
+ } else {
+ HandlerThread headlerThread = new HandlerThread(mLogTag);
+ headlerThread.start();
+ mHandler = new GbaManagerHandler(headlerThread.getLooper());
+ }
if (mReleaseTime < 0) {
mHandler.sendEmptyMessage(EVENT_BIND_SERVICE);
@@ -224,9 +234,15 @@
* create a GbaManager instance for a sub
*/
public static GbaManager make(Context context, int subId,
- String servicePackageName, int releaseTime) {
- GbaManager gm = new GbaManager(context, subId, servicePackageName, releaseTime,
- RcsStats.getInstance());
+ String servicePackageName, int releaseTime, FeatureFlags featureFlags) {
+ GbaManager gm;
+ if (featureFlags.threadShred()) {
+ gm = new GbaManager(context, subId, servicePackageName, releaseTime,
+ RcsStats.getInstance(), WorkerThread.get().getLooper(), featureFlags);
+ } else {
+ gm = new GbaManager(context, subId, servicePackageName, releaseTime,
+ RcsStats.getInstance(), null, featureFlags);
+ }
synchronized (sGbaManagers) {
sGbaManagers.put(subId, gm);
}
@@ -521,11 +537,15 @@
@VisibleForTesting
public void destroy() {
mHandler.removeCallbacksAndMessages(null);
- mHandler.getLooper().quit();
+ if (!mFeatureFlags.threadShred()) {
+ mHandler.getLooper().quit();
+ }
mRequestQueue.clear();
mCallbacks.clear();
unbindService();
- sGbaManagers.remove(mSubId);
+ synchronized (sGbaManagers) {
+ sGbaManagers.remove(mSubId);
+ }
}
private void logv(String msg) {
diff --git a/src/java/com/android/internal/telephony/RadioInterfaceCapabilityController.java b/src/java/com/android/internal/telephony/RadioInterfaceCapabilityController.java
index 4d9196e..e681280 100644
--- a/src/java/com/android/internal/telephony/RadioInterfaceCapabilityController.java
+++ b/src/java/com/android/internal/telephony/RadioInterfaceCapabilityController.java
@@ -26,6 +26,8 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.Flags;
+import com.android.internal.telephony.util.WorkerThread;
import com.android.telephony.Rlog;
import java.io.FileDescriptor;
@@ -55,10 +57,19 @@
final CommandsInterface commandsInterface) {
synchronized (RadioInterfaceCapabilityController.class) {
if (sInstance == null) {
- final HandlerThread handlerThread = new HandlerThread("RHC");
- handlerThread.start();
- sInstance = new RadioInterfaceCapabilityController(radioConfig, commandsInterface,
- handlerThread.getLooper());
+ if (Flags.threadShred()) {
+ sInstance = new RadioInterfaceCapabilityController(
+ radioConfig,
+ commandsInterface,
+ WorkerThread.get().getLooper());
+ } else {
+ final HandlerThread handlerThread = new HandlerThread("RHC");
+ handlerThread.start();
+ sInstance = new RadioInterfaceCapabilityController(
+ radioConfig,
+ commandsInterface,
+ handlerThread.getLooper());
+ }
} else {
Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
}
diff --git a/src/java/com/android/internal/telephony/TelephonyCountryDetector.java b/src/java/com/android/internal/telephony/TelephonyCountryDetector.java
index 1e07bc3..d5b7fad 100644
--- a/src/java/com/android/internal/telephony/TelephonyCountryDetector.java
+++ b/src/java/com/android/internal/telephony/TelephonyCountryDetector.java
@@ -43,6 +43,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.util.WorkerThread;
import java.util.ArrayList;
import java.util.HashMap;
@@ -205,12 +206,19 @@
public static synchronized TelephonyCountryDetector getInstance(@NonNull Context context,
FeatureFlags featureFlags) {
if (sInstance == null) {
- HandlerThread handlerThread = new HandlerThread("TelephonyCountryDetector");
- handlerThread.start();
- sInstance = new TelephonyCountryDetector(handlerThread.getLooper(), context,
- context.getSystemService(LocationManager.class),
- context.getSystemService(ConnectivityManager.class),
- featureFlags);
+ if (featureFlags.threadShred()) {
+ sInstance = new TelephonyCountryDetector(WorkerThread.get().getLooper(), context,
+ context.getSystemService(LocationManager.class),
+ context.getSystemService(ConnectivityManager.class),
+ featureFlags);
+ } else {
+ HandlerThread handlerThread = new HandlerThread("TelephonyCountryDetector");
+ handlerThread.start();
+ sInstance = new TelephonyCountryDetector(handlerThread.getLooper(), context,
+ context.getSystemService(LocationManager.class),
+ context.getSystemService(ConnectivityManager.class),
+ featureFlags);
+ }
}
return sInstance;
}
diff --git a/src/java/com/android/internal/telephony/analytics/TelephonyAnalytics.java b/src/java/com/android/internal/telephony/analytics/TelephonyAnalytics.java
index e74e40e..063ee45 100644
--- a/src/java/com/android/internal/telephony/analytics/TelephonyAnalytics.java
+++ b/src/java/com/android/internal/telephony/analytics/TelephonyAnalytics.java
@@ -47,10 +47,12 @@
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.telephony.InboundSmsHandler;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.ServiceStateTracker;
+import com.android.internal.telephony.flags.Flags;
import com.android.telephony.Rlog;
import java.io.FileDescriptor;
@@ -116,9 +118,14 @@
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
mSlotIndex = mPhone.getPhoneId();
- mHandlerThread = new HandlerThread(TelephonyAnalytics.class.getSimpleName());
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
+ if (Flags.threadShred()) {
+ mHandlerThread = null; // TODO: maybe this doesn't need to be a member variable
+ mHandler = new Handler(BackgroundThread.get().getLooper());
+ } else {
+ mHandlerThread = new HandlerThread(TelephonyAnalytics.class.getSimpleName());
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
mExecutorService = Executors.newSingleThreadExecutor();
mTelephonyAnalyticsUtil = TelephonyAnalyticsUtil.getInstance(mContext);
initializeAnalyticsClasses();
diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java
index 5fdb8ce..569a9c3 100644
--- a/src/java/com/android/internal/telephony/cat/CatService.java
+++ b/src/java/com/android/internal/telephony/cat/CatService.java
@@ -62,6 +62,7 @@
import com.android.internal.telephony.uicc.UiccCardApplication;
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.uicc.UiccProfile;
+import com.android.internal.telephony.util.WorkerThread;
import java.io.ByteArrayOutputStream;
import java.util.List;
@@ -228,9 +229,11 @@
*/
public static CatService getInstance(CommandsInterface ci,
Context context, UiccProfile uiccProfile, int slotId) {
- if (sCatServiceThread == null) {
- sCatServiceThread = new HandlerThread("CatServiceThread");
- sCatServiceThread.start();
+ if (!sFlags.threadShred()) {
+ if (sCatServiceThread == null) {
+ sCatServiceThread = new HandlerThread("CatServiceThread");
+ sCatServiceThread.start();
+ }
}
UiccCardApplication ca = null;
IccFileHandler fh = null;
@@ -259,8 +262,13 @@
|| uiccProfile == null) {
return null;
}
- sInstance[slotId] = new CatService(ci, ca, ir, context, fh, uiccProfile, slotId,
- sCatServiceThread.getLooper());
+ if (sFlags.threadShred()) {
+ sInstance[slotId] = new CatService(ci, ca, ir, context, fh, uiccProfile, slotId,
+ WorkerThread.get().getLooper());
+ } else {
+ sInstance[slotId] = new CatService(ci, ca, ir, context, fh, uiccProfile, slotId,
+ sCatServiceThread.getLooper());
+ }
} else if ((ir != null) && (mIccRecords != ir)) {
if (mIccRecords != null) {
mIccRecords.unregisterForRecordsLoaded(sInstance[slotId]);
diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java
index e4ae592..a8fead4 100644
--- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java
+++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java
@@ -44,7 +44,9 @@
import com.android.internal.telephony.IDomainSelectionServiceController;
import com.android.internal.telephony.ITransportSelectorCallback;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.internal.telephony.util.WorkerThread;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -80,10 +82,9 @@
long getMaximumDelay();
}
- private final HandlerThread mHandlerThread =
- new HandlerThread("DomainSelectionControllerHandler");
-
+ private HandlerThread mHandlerThread; // effectively final
private final Handler mHandler;
+
// Only added or removed, never accessed on purpose.
private final LocalLog mLocalLog = new LocalLog(30);
@@ -255,9 +256,15 @@
@Nullable Looper looper, @Nullable BindRetry bindRetry) {
mContext = context;
+ mHandlerThread = null;
if (looper == null) {
- mHandlerThread.start();
- looper = mHandlerThread.getLooper();
+ if (Flags.threadShred()) {
+ looper = WorkerThread.get().getLooper();
+ } else {
+ mHandlerThread = new HandlerThread("DomainSelectionControllerHandler");
+ mHandlerThread.start();
+ looper = mHandlerThread.getLooper();
+ }
}
mHandler = new DomainSelectionControllerHandler(looper);
diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java
index b95911f..73ea190 100644
--- a/src/java/com/android/internal/telephony/ims/ImsResolver.java
+++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java
@@ -63,6 +63,7 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.telephony.PhoneConfigurationManager;
import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.util.WorkerThread;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
@@ -138,7 +139,8 @@
// Delay between dynamic ImsService queries.
private static final int DELAY_DYNAMIC_QUERY_MS = 5000;
- private static final HandlerThread sHandlerThread = new HandlerThread(TAG);
+
+ private static HandlerThread sHandlerThread;
private static ImsResolver sInstance;
@@ -149,9 +151,15 @@
String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo,
FeatureFlags featureFlags) {
if (sInstance == null) {
- sHandlerThread.start();
- sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName,
- numSlots, repo, sHandlerThread.getLooper(), featureFlags);
+ if (featureFlags.threadShred()) {
+ sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName,
+ numSlots, repo, WorkerThread.get().getLooper(), featureFlags);
+ } else {
+ sHandlerThread = new HandlerThread(TAG);
+ sHandlerThread.start();
+ sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName,
+ numSlots, repo, sHandlerThread.getLooper(), featureFlags);
+ }
}
}
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
index 37c10eb..c61c7eb 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
@@ -28,6 +28,7 @@
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IInterface;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.permission.LegacyPermissionManager;
@@ -51,6 +52,7 @@
import com.android.internal.telephony.ExponentialBackoff;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.internal.telephony.util.WorkerThread;
import java.io.PrintWriter;
import java.util.HashSet;
@@ -264,7 +266,7 @@
// Enable ImsServiceControllerTest and SipDelegateManagerTest cases if this is re-enabled.
private static final boolean ENFORCE_SINGLE_SERVICE_FOR_SIP_TRANSPORT = false;
private final ComponentName mComponentName;
- private final HandlerThread mHandlerThread = new HandlerThread("ImsServiceControllerHandler");
+ private final HandlerThread mHandlerThread;
private final Handler mHandler;
private final LegacyPermissionManager mPermissionManager;
private final FeatureFlags mFeatureFlags;
@@ -362,8 +364,17 @@
mContext = context;
mComponentName = componentName;
mCallbacks = callbacks;
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
+ Looper looper;
+ if (featureFlags.threadShred()) {
+ mHandlerThread = null;
+ mHandler = new Handler(WorkerThread.get().getLooper());
+ looper = WorkerThread.get().getLooper();
+ } else {
+ mHandlerThread = new HandlerThread("ImsServiceControllerHandler");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ looper = mHandlerThread.getLooper();
+ }
mBackoff = new ExponentialBackoff(
mRebindRetry.getStartDelay(),
mRebindRetry.getMaximumDelay(),
@@ -373,7 +384,7 @@
mPermissionManager = (LegacyPermissionManager) mContext.getSystemService(
Context.LEGACY_PERMISSION_SERVICE);
mRepo = repo;
- mImsEnablementTracker = new ImsEnablementTracker(mHandlerThread.getLooper(), componentName);
+ mImsEnablementTracker = new ImsEnablementTracker(looper, componentName);
mFeatureFlags = featureFlags;
mPackageManager = mContext.getPackageManager();
if (mPackageManager != null) {
@@ -404,6 +415,7 @@
mRepo = repo;
mFeatureFlags = featureFlags;
mImsEnablementTracker = new ImsEnablementTracker(handler.getLooper(), componentName);
+ mHandlerThread = null;
}
/**
diff --git a/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java b/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java
index 079ff03..696c9ce 100644
--- a/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java
+++ b/src/java/com/android/internal/telephony/metrics/DataConnectionStateTracker.java
@@ -29,8 +29,10 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TelephonyStatsLog;
+import com.android.internal.telephony.flags.Flags;
import java.util.HashMap;
import java.util.List;
@@ -76,10 +78,14 @@
};
private DataConnectionStateTracker() {
- HandlerThread handlerThread =
- new HandlerThread(DataConnectionStateTracker.class.getSimpleName());
- handlerThread.start();
- mExecutor = new HandlerExecutor(new Handler(handlerThread.getLooper()));
+ if (Flags.threadShred()) {
+ mExecutor = BackgroundThread.getExecutor();
+ } else {
+ HandlerThread handlerThread =
+ new HandlerThread(DataConnectionStateTracker.class.getSimpleName());
+ handlerThread.start();
+ mExecutor = new HandlerExecutor(new Handler(handlerThread.getLooper()));
+ }
}
/** Getting or Creating DataConnectionStateTracker based on phoneId */
diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java
index cd5b7d6..e7352a4 100644
--- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java
+++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java
@@ -47,6 +47,7 @@
import android.telephony.data.DataCallResponse.LinkStatus;
import android.text.TextUtils;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyStatsLog;
@@ -143,9 +144,14 @@
mPhone = phone;
mFeatureFlags = featureFlags;
- HandlerThread handlerThread = new HandlerThread(mTag + "-thread");
- handlerThread.start();
- mHandler = new Handler(handlerThread.getLooper());
+ if (mFeatureFlags.threadShred()) {
+ mHandler = new Handler(BackgroundThread.get().getLooper());
+ } else {
+ HandlerThread handlerThread = new HandlerThread(mTag + "-thread");
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+ }
+
mTelephonyManager = mPhone.getContext().getSystemService(TelephonyManager.class);
dataNetworkController.registerDataNetworkControllerCallback(
diff --git a/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java b/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java
index 9ab52fb..dc0ee4e 100644
--- a/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java
+++ b/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java
@@ -28,21 +28,32 @@
import android.os.HandlerExecutor;
import android.os.HandlerThread;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.flags.Flags;
/** Device state information like the fold state. */
public class DeviceStateHelper {
private int mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN;
public DeviceStateHelper(Context context) {
- HandlerThread mHandlerThread = new HandlerThread("DeviceStateHelperThread");
- mHandlerThread.start();
- context.getSystemService(DeviceStateManager.class)
- .registerCallback(
- new HandlerExecutor(new Handler(mHandlerThread.getLooper())),
- state -> {
- updateFoldState(state.getIdentifier());
- });
+ if (Flags.threadShred()) {
+ context.getSystemService(DeviceStateManager.class)
+ .registerCallback(
+ BackgroundThread.getExecutor(),
+ state -> {
+ updateFoldState(state.getIdentifier());
+ });
+ } else {
+ HandlerThread mHandlerThread = new HandlerThread("DeviceStateHelperThread");
+ mHandlerThread.start();
+ context.getSystemService(DeviceStateManager.class)
+ .registerCallback(
+ new HandlerExecutor(new Handler(mHandlerThread.getLooper())),
+ state -> {
+ updateFoldState(state.getIdentifier());
+ });
+ }
}
private void updateFoldState(int posture) {
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index 581d54c..8f9a96b 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -29,6 +29,8 @@
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.nano.PersistAtomsProto.CarrierIdMismatch;
import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteControllerStats;
import com.android.internal.telephony.nano.PersistAtomsProto.CarrierRoamingSatelliteSession;
@@ -263,9 +265,15 @@
mAtoms = loadAtomsFromFile();
mVoiceCallRatTracker = VoiceCallRatTracker.fromProto(mAtoms.voiceCallRatUsage);
- mHandlerThread = new HandlerThread("PersistAtomsThread");
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
+ if (Flags.threadShred()) {
+ mHandlerThread = null;
+ mHandler = new Handler(BackgroundThread.get().getLooper());
+ } else {
+ // TODO: we might be able to make mHandlerThread a local variable
+ mHandlerThread = new HandlerThread("PersistAtomsThread");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
mSaveImmediately = false;
}
diff --git a/src/java/com/android/internal/telephony/metrics/VonrHelper.java b/src/java/com/android/internal/telephony/metrics/VonrHelper.java
index 8f14a86..24c0945 100644
--- a/src/java/com/android/internal/telephony/metrics/VonrHelper.java
+++ b/src/java/com/android/internal/telephony/metrics/VonrHelper.java
@@ -24,6 +24,7 @@
import android.os.HandlerThread;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.flags.FeatureFlags;
@@ -39,14 +40,19 @@
private final @NonNull FeatureFlags mFlags;
private Handler mHandler;
+ private Handler mHandlerThread;
private Map<Integer, Boolean> mPhoneVonrState = new ConcurrentHashMap<>();
public VonrHelper(@NonNull FeatureFlags featureFlags) {
this.mFlags = featureFlags;
if (mFlags.vonrEnabledMetric()) {
- HandlerThread mHandlerThread = new HandlerThread("VonrHelperThread");
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
+ if (mFlags.threadShred()) {
+ mHandler = new Handler(BackgroundThread.get().getLooper());
+ } else {
+ HandlerThread mHandlerThread = new HandlerThread("VonrHelperThread");
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ }
}
}
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 0f33463..d5fc541 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -178,6 +178,7 @@
import com.android.internal.telephony.subscription.SubscriptionManagerService;
import com.android.internal.telephony.util.ArrayUtils;
import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.internal.telephony.util.WorkerThread;
import com.android.internal.util.FunctionalUtils;
import java.util.ArrayList;
@@ -834,9 +835,15 @@
*/
public static void make(@NonNull Context context, @NonNull FeatureFlags featureFlags) {
if (sInstance == null) {
- HandlerThread satelliteThread = new HandlerThread(TAG);
- satelliteThread.start();
- sInstance = new SatelliteController(context, satelliteThread.getLooper(), featureFlags);
+ if (featureFlags.threadShred()) {
+ sInstance = new SatelliteController(
+ context, WorkerThread.get().getLooper(), featureFlags);
+ } else {
+ HandlerThread satelliteThread = new HandlerThread(TAG);
+ satelliteThread.start();
+ sInstance = new SatelliteController(
+ context, satelliteThread.getLooper(), featureFlags);
+ }
}
}
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 0c993cf..83c11ef 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -116,6 +116,7 @@
import com.android.internal.telephony.uicc.UiccSlot;
import com.android.internal.telephony.util.ArrayUtils;
import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.internal.telephony.util.WorkerThread;
import com.android.telephony.Rlog;
import java.io.FileDescriptor;
@@ -491,10 +492,14 @@
mUiccController = UiccController.getInstance();
mHandler = new Handler(looper);
- HandlerThread backgroundThread = new HandlerThread(LOG_TAG);
- backgroundThread.start();
+ if (mFeatureFlags.threadShred()) {
+ mBackgroundHandler = new Handler(WorkerThread.get().getLooper());
+ } else {
+ HandlerThread backgroundThread = new HandlerThread(LOG_TAG);
+ backgroundThread.start();
- mBackgroundHandler = new Handler(backgroundThread.getLooper());
+ mBackgroundHandler = new Handler(backgroundThread.getLooper());
+ }
mDefaultVoiceSubId = new WatchedInt(Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
@@ -549,12 +554,22 @@
mSimState = new int[mTelephonyManager.getSupportedModemCount()];
Arrays.fill(mSimState, TelephonyManager.SIM_STATE_UNKNOWN);
- // Create a separate thread for subscription database manager. The database will be updated
- // from a different thread.
- HandlerThread handlerThread = new HandlerThread(LOG_TAG);
- handlerThread.start();
- mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(context,
- handlerThread.getLooper(), mFeatureFlags,
+ Looper dbLooper = null;
+
+ if (mFeatureFlags.threadShred()) {
+ dbLooper = WorkerThread.get().getLooper();
+ } else {
+ // Create a separate thread for subscription database manager.
+ // The database will be updated from a different thread.
+ HandlerThread handlerThread = new HandlerThread(LOG_TAG);
+ handlerThread.start();
+ dbLooper = handlerThread.getLooper();
+ }
+
+ mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(
+ context,
+ dbLooper,
+ mFeatureFlags,
new SubscriptionDatabaseManagerCallback(mHandler::post) {
/**
* Called when database has been loaded into the cache.
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GbaManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/GbaManagerTest.java
index 8898a0f..e97b1c0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GbaManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GbaManagerTest.java
@@ -42,6 +42,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
import android.telephony.IBootstrapAuthenticationCallback;
import android.telephony.TelephonyManager;
import android.telephony.gba.GbaAuthRequest;
@@ -52,6 +53,7 @@
import android.testing.TestableLooper;
import android.util.Log;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.metrics.RcsStats;
import org.junit.After;
@@ -97,30 +99,44 @@
mMockGbaServiceBinder = mock(IGbaService.class);
mMockCallback = mock(IBootstrapAuthenticationCallback.class);
mMockRcsStats = mock(RcsStats.class);
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
when(mMockContext.bindServiceAsUser(any(), any(), anyInt(), any(UserHandle.class)))
.thenReturn(true);
when(mMockGbaServiceBinder.asBinder()).thenReturn(mMockBinder);
- mTestGbaManager = new GbaManager(mMockContext, TEST_SUB_ID, null, 0, mMockRcsStats);
- mHandler = mTestGbaManager.getHandler();
- try {
- mLooper = new TestableLooper(mHandler.getLooper());
- } catch (Exception e) {
- fail("Unable to create looper from handler.");
+
+ if (mFeatureFlags.threadShred()) {
+ mTestGbaManager = new GbaManager(
+ mMockContext, TEST_SUB_ID, null, 0, mMockRcsStats,
+ TestableLooper.get(this).getLooper(), mFeatureFlags);
+ monitorTestableLooper(TestableLooper.get(this));
+ } else {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mTestGbaManager = new GbaManager(
+ mMockContext, TEST_SUB_ID, null, 0, mMockRcsStats, null, mFeatureFlags);
+ mHandler = mTestGbaManager.getHandler();
+ try {
+ mLooper = new TestableLooper(mHandler.getLooper());
+ } catch (Exception e) {
+ fail("Unable to create looper from handler.");
+ }
+ monitorTestableLooper(mLooper);
}
- monitorTestableLooper(mLooper);
}
@After
public void tearDown() throws Exception {
log("tearDown");
- mTestGbaManager.destroy();
+ if (mFeatureFlags.threadShred()) {
+ if (mTestGbaManager != null) mTestGbaManager.destroy();
+ } else {
+ mTestGbaManager.destroy();
+ }
super.tearDown();
}
@Test
+ @EnableFlags(Flags.FLAG_THREAD_SHRED)
public void testFailOnRequest() throws Exception {
GbaAuthRequest request = createDefaultRequest();
@@ -134,6 +150,7 @@
}
@Test
+ @EnableFlags(Flags.FLAG_THREAD_SHRED)
public void testBindServiceOnRequest() throws Exception {
mTestGbaManager.overrideServicePackage(TEST_DEFAULT_SERVICE_NAME.getPackageName(), 123);
GbaAuthRequest request = createDefaultRequest();
@@ -148,6 +165,7 @@
}
@Test
+ @EnableFlags(Flags.FLAG_THREAD_SHRED)
public void testFailAndRetryOnRequest() throws RemoteException {
when(mMockContext.bindServiceAsUser(any(), any(), anyInt(), any(UserHandle.class)))
.thenReturn(false);
@@ -168,6 +186,7 @@
}
@Test
+ @EnableFlags(Flags.FLAG_THREAD_SHRED)
public void testBindServiceWhenPackageNameChanged() {
mTestGbaManager.overrideServicePackage(TEST_DEFAULT_SERVICE_NAME.getPackageName(), 123);
mTestGbaManager.overrideReleaseTime(RELEASE_TIME_60S);
@@ -187,6 +206,7 @@
}
@Test
+ @EnableFlags(Flags.FLAG_THREAD_SHRED)
public void testBindServiceWhenReleaseTimeChanged() {
mTestGbaManager.overrideServicePackage(TEST_DEFAULT_SERVICE_NAME.getPackageName(), 123);
mTestGbaManager.overrideReleaseTime(RELEASE_NEVER);
@@ -199,6 +219,7 @@
}
@Test
+ @EnableFlags(Flags.FLAG_THREAD_SHRED)
public void testDontBindServiceWhenPackageNameChanged() {
mTestGbaManager.overrideServicePackage(TEST_SERVICE2_NAME.getPackageName(), 123);
@@ -210,6 +231,7 @@
}
@Test
+ @EnableFlags(Flags.FLAG_THREAD_SHRED)
public void testDontBindServiceWhenReleaseTimeChanged() {
mTestGbaManager.overrideServicePackage(TEST_DEFAULT_SERVICE_NAME.getPackageName(), 123);
mTestGbaManager.overrideReleaseTime(RELEASE_TIME_60S);
@@ -222,6 +244,7 @@
}
@Test
+ @EnableFlags(Flags.FLAG_THREAD_SHRED)
public void testMetricsGbaEvent() throws Exception {
mTestGbaManager.overrideServicePackage(TEST_DEFAULT_SERVICE_NAME.getPackageName(), 123);
mTestGbaManager.overrideReleaseTime(RELEASE_NEVER);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 6517b15..0817b7a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -143,6 +143,7 @@
import com.android.internal.telephony.uicc.UiccPort;
import com.android.internal.telephony.uicc.UiccProfile;
import com.android.internal.telephony.uicc.UiccSlot;
+import com.android.internal.telephony.util.WorkerThread;
import com.android.server.pm.permission.LegacyPermissionManagerService;
import org.mockito.Mockito;
@@ -583,6 +584,7 @@
doReturn(true).when(mFeatureFlags).hsumBroadcast();
doReturn(true).when(mFeatureFlags).hsumPackageManager();
+ WorkerThread.reset();
TelephonyManager.disableServiceHandleCaching();
PropertyInvalidatedCache.disableForTestMode();
// For testing do not allow Log.WTF as it can cause test process to crash
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
index adc0c75..a92ba8b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -223,7 +223,10 @@
mFeatureFlags);
monitorTestableLooper(new TestableLooper(getBackgroundHandler().getLooper()));
- monitorTestableLooper(new TestableLooper(getSubscriptionDatabaseManager().getLooper()));
+
+ if (!mFeatureFlags.threadShred()) {
+ monitorTestableLooper(new TestableLooper(getSubscriptionDatabaseManager().getLooper()));
+ }
doAnswer(invocation -> {
((Runnable) invocation.getArguments()[0]).run();