Async Initialize CarrierPrivilegesTracker

Create a separate HandlerThread to offload the heavyweight
initialization required for CarrierPrivilegesTracker. Push
all async events to that thread until the init is done, then
process the events in-order and turn down the thread so that
there isn't another unnecessary thread hanging around once
the heavy work is done.

Bug: 357096337
Test: atest CarrierPrivilegesTrackerTest
Flag: async_init_carrier_privileges_tracker
Change-Id: Idba6bc2191183568ad5fb3fd96e4219ea5ddfd99
diff --git a/flags/Android.bp b/flags/Android.bp
index 1885032..edcfc3f 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -33,6 +33,7 @@
         "subscription.aconfig",
         "uicc.aconfig",
         "satellite.aconfig",
-        "iwlan.aconfig"
+        "iwlan.aconfig",
+        "carrier.aconfig",
     ],
 }
diff --git a/flags/carrier.aconfig b/flags/carrier.aconfig
new file mode 100644
index 0000000..dca2ad3
--- /dev/null
+++ b/flags/carrier.aconfig
@@ -0,0 +1,11 @@
+package: "com.android.internal.telephony.flags"
+container: "system"
+
+# OWNER=nharold TARGET=24Q4
+flag {
+    name: "async_init_carrier_privileges_tracker"
+    is_exported: true
+    namespace: "telephony"
+    description: "Offload the heavyweight initialization of CarrierPrivilegesTracker to a worker thread"
+    bug:"357096337"
+}
diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java
index e6bfb9b..6326d6c 100644
--- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java
@@ -46,6 +46,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PersistableBundle;
@@ -177,6 +178,8 @@
     private static final int ACTION_SET_TEST_OVERRIDE_CARRIER_SERVICE_PACKAGE = 11;
 
     private final Context mContext;
+    @NonNull
+    private final FeatureFlags mFeatureFlags;
     private final Phone mPhone;
     private final PackageManager mPackageManager;
     private final UserManager mUserManager;
@@ -224,8 +227,7 @@
             "mPrivilegedPackageInfoLock.writeLock()"})
     private boolean mSimIsReadyButNotLoaded = false;
 
-    @NonNull
-    private final FeatureFlags mFeatureFlags;
+    private volatile Handler mCurrentHandler;
 
     /** Small snapshot to hold package names and UIDs of privileged packages. */
     private static final class PrivilegedPackageInfo {
@@ -301,7 +303,9 @@
                                 return;
                             }
 
-                            sendMessage(obtainMessage(ACTION_SIM_STATE_UPDATED, slotId, simState));
+                            mCurrentHandler.sendMessage(
+                                    mCurrentHandler.obtainMessage(
+                                            ACTION_SIM_STATE_UPDATED, slotId, simState));
                             break;
                         }
                         case Intent.ACTION_PACKAGE_ADDED: // fall through
@@ -333,19 +337,21 @@
                                     ? ACTION_PACKAGE_REMOVED_OR_DISABLED_BY_USER
                                     : ACTION_PACKAGE_ADDED_REPLACED_OR_CHANGED;
 
-                            sendMessage(obtainMessage(what, pkgName));
+                            mCurrentHandler.sendMessage(
+                                    mCurrentHandler.obtainMessage(what, pkgName));
                             break;
                         }
                     }
                 }
             };
 
-    public CarrierPrivilegesTracker(@NonNull Looper looper, @NonNull Phone phone,
-            @NonNull Context context, @NonNull FeatureFlags flags) {
+    public CarrierPrivilegesTracker(
+            @NonNull Looper looper, @NonNull Phone phone,
+            @NonNull Context context, @NonNull FeatureFlags featureFlags) {
         super(looper);
-        mContext = context;
-        mFeatureFlags = flags;
         mPhone = phone;
+        mContext = context;
+        mFeatureFlags = featureFlags;
         mPackageManager = mContext.getPackageManager();
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mCarrierConfigManager =
@@ -361,6 +367,56 @@
                 (TelephonyRegistryManager)
                         mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
 
+        if (mFeatureFlags.asyncInitCarrierPrivilegesTracker()) {
+            final Object localLock = new Object();
+            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;
+                    }
+                }
+            };
+        } else {
+            mCurrentHandler = this;
+        }
+
+        mCurrentHandler.sendMessage(obtainMessage(ACTION_INITIALIZE_TRACKER));
+
         IntentFilter certFilter = new IntentFilter();
         certFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
         certFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
@@ -389,7 +445,6 @@
             mContext.registerReceiver(mIntentReceiver, packageFilter);
         }
 
-        sendMessage(obtainMessage(ACTION_INITIALIZE_TRACKER));
     }
 
     @Override
@@ -497,7 +552,7 @@
                     && mClearUiccRulesUptimeMillis == CLEAR_UICC_RULE_NOT_SCHEDULED) {
                 mClearUiccRulesUptimeMillis =
                         SystemClock.uptimeMillis() + CLEAR_UICC_RULES_DELAY_MILLIS;
-                sendMessageAtTime(obtainMessage(ACTION_CLEAR_UICC_RULES),
+                mCurrentHandler.sendMessageAtTime(obtainMessage(ACTION_CLEAR_UICC_RULES),
                         mClearUiccRulesUptimeMillis);
                 mLocalLog.log("SIM is gone, simState=" + TelephonyManager.simStateToString(simState)
                         + ". Delay " + TimeUnit.MILLISECONDS.toSeconds(
@@ -920,7 +975,8 @@
      * @see TelephonyManager#setCarrierTestOverride
      */
     public void setTestOverrideCarrierPrivilegeRules(@Nullable String carrierPrivilegeRules) {
-        sendMessage(obtainMessage(ACTION_SET_TEST_OVERRIDE_RULE, carrierPrivilegeRules));
+        mCurrentHandler.sendMessage(
+                obtainMessage(ACTION_SET_TEST_OVERRIDE_RULE, carrierPrivilegeRules));
     }
 
     /**
@@ -936,7 +992,7 @@
      * @see TelephonyManager#setCarrierServicePackageOverride
      */
     public void setTestOverrideCarrierServicePackage(@Nullable String carrierServicePackage) {
-        sendMessage(obtainMessage(
+        mCurrentHandler.sendMessage(obtainMessage(
                 ACTION_SET_TEST_OVERRIDE_CARRIER_SERVICE_PACKAGE, carrierServicePackage));
     }
 
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 5d59327..2e1a89f 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -391,8 +391,8 @@
 
         mCarrierResolver = mTelephonyComponentFactory.inject(CarrierResolver.class.getName())
                 .makeCarrierResolver(this, featureFlags);
-        mCarrierPrivilegesTracker = new CarrierPrivilegesTracker(Looper.myLooper(), this, context,
-                featureFlags);
+        mCarrierPrivilegesTracker = new CarrierPrivilegesTracker(
+                Looper.myLooper(), this, context, featureFlags);
 
         getCarrierActionAgent().registerForCarrierAction(
                 CarrierActionAgent.CARRIER_ACTION_SET_METERED_APNS_ENABLED, this,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java
index a860dff..1c58ef2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java
@@ -220,8 +220,9 @@
         // Capture CarrierConfigChangeListener to emulate the carrier config change notification
         ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor =
                 ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
-        CarrierPrivilegesTracker cpt = new CarrierPrivilegesTracker(mTestableLooper.getLooper(),
-                mPhone, mContext, mFeatureFlags);
+        CarrierPrivilegesTracker cpt =
+                new CarrierPrivilegesTracker(
+                        mTestableLooper.getLooper(), mPhone, mContext, mFeatureFlags);
         verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
                 listenerArgumentCaptor.capture());
         mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0);