Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62f17c0a authored by Rambo Wang's avatar Rambo Wang Committed by Automerger Merge Worker
Browse files

Merge "Make carrier service persistent binding more robust" am: e4ab1a35

parents 8fa4ae86 e4ab1a35
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Message;
import android.os.Process;
@@ -47,6 +48,8 @@ import com.android.internal.telephony.util.TelephonyUtils;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Set;

/**
 * Manages long-lived bindings to carrier services
@@ -71,6 +74,8 @@ public class CarrierServiceBindHelper {
    public SparseArray<AppBinding> mBindings = new SparseArray();
    @VisibleForTesting
    public SparseArray<String> mLastSimState = new SparseArray<>();
    // TODO(b/201423849): Clean up PackageChangeReceiver/UserUnlockedReceiver/SIM State change if
    // CarrierServiceChangeCallback can cover the cases
    private final PackageChangeReceiver mPackageMonitor = new CarrierServicePackageMonitor();
    private final LocalLog mLocalLog = new LocalLog(100);

@@ -90,6 +95,30 @@ public class CarrierServiceBindHelper {
        }
    };

    private class CarrierServiceChangeCallback implements
            TelephonyManager.CarrierPrivilegesCallback {
        final int mPhoneId;

        CarrierServiceChangeCallback(int phoneId) {
            this.mPhoneId = phoneId;
        }

        @Override
        public void onCarrierPrivilegesChanged(Set<String> privilegedPackageNames,
                Set<Integer> privilegedUids) {
            // Ignored, not interested here
        }

        @Override
        public void onCarrierServiceChanged(String carrierServicePackageName,
                int carrierServiceUid) {
            logdWithLocalLog("onCarrierServiceChanged, carrierServicePackageName="
                    + carrierServicePackageName + ", carrierServiceUid=" + carrierServiceUid
                    + ", mPhoneId=" + mPhoneId);
            mHandler.sendMessage(mHandler.obtainMessage(EVENT_REBIND, mPhoneId));
        }
    }

    private static final int EVENT_REBIND = 0;
    @VisibleForTesting
    public static final int EVENT_PERFORM_IMMEDIATE_UNBIND = 1;
@@ -123,6 +152,8 @@ public class CarrierServiceBindHelper {
                case EVENT_MULTI_SIM_CONFIG_CHANGED:
                    updateBindingsAndSimStates();
                    break;
                default:
                    Log.e(LOG_TAG, "Unsupported event received: " + msg.what);
            }
        }
    };
@@ -162,6 +193,7 @@ public class CarrierServiceBindHelper {

        // If prevLen > newLen, dispose AppBinding and simState objects.
        for (int phoneId = newLen; phoneId < prevLen; phoneId++) {
            mBindings.get(phoneId).tearDown();
            mBindings.get(phoneId).unbind(true);
            mBindings.delete(phoneId);
            mLastSimState.delete(phoneId);
@@ -193,9 +225,23 @@ public class CarrierServiceBindHelper {
        private String carrierPackage;
        private String carrierServiceClass;
        private long mUnbindScheduledUptimeMillis = -1;
        private final CarrierServiceChangeCallback mCarrierServiceChangeCallback;

        public AppBinding(int phoneId) {
            this.phoneId = phoneId;
            this.mCarrierServiceChangeCallback = new CarrierServiceChangeCallback(phoneId);
            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
            if (tm != null) {
                tm.registerCarrierPrivilegesCallback(phoneId, new HandlerExecutor(mHandler),
                        mCarrierServiceChangeCallback);
            }
        }

        public void tearDown() {
            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
            if (tm != null && mCarrierServiceChangeCallback != null) {
                tm.unregisterCarrierPrivilegesCallback(mCarrierServiceChangeCallback);
            }
        }

        public int getPhoneId() {
@@ -365,6 +411,7 @@ public class CarrierServiceBindHelper {
            pw.println("  unbindCount: " + unbindCount);
            pw.println("  lastUnbindMillis: " + lastUnbindMillis);
            pw.println("  mUnbindScheduledUptimeMillis: " + mUnbindScheduledUptimeMillis);
            pw.println("  mCarrierServiceChangeCallback: " + mCarrierServiceChangeCallback);
            pw.println();
        }
    }
@@ -405,27 +452,32 @@ public class CarrierServiceBindHelper {
    private class CarrierServicePackageMonitor extends PackageChangeReceiver {
        @Override
        public void onPackageAdded(String packageName) {
            logdWithLocalLog("onPackageAdded: " + packageName);
            evaluateBinding(packageName, true /* forceUnbind */);
        }

        @Override
        public void onPackageRemoved(String packageName) {
            logdWithLocalLog("onPackageRemoved: " + packageName);
            evaluateBinding(packageName, true /* forceUnbind */);
        }

        @Override
        public void onPackageUpdateFinished(String packageName) {
            logdWithLocalLog("onPackageUpdateFinished: " + packageName);
            evaluateBinding(packageName, true /* forceUnbind */);
        }

        @Override
        public void onPackageModified(String packageName) {
            logdWithLocalLog("onPackageModified: " + packageName);
            evaluateBinding(packageName, false /* forceUnbind */);
        }

        @Override
        public void onHandleForceStop(String[] packages, boolean doit) {
            if (doit) {
                logdWithLocalLog("onHandleForceStop: " + Arrays.toString(packages));
                for (String packageName : packages) {
                    evaluateBinding(packageName, true /* forceUnbind */);
                }
+43 −0
Original line number Diff line number Diff line
@@ -18,10 +18,15 @@ package com.android.internal.telephony;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

import android.os.Message;
import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -30,10 +35,14 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class CarrierServiceBindHelperTest extends TelephonyTest {
    private static final int PHONE_ID_0 = 0;
    private static final int PHONE_ID_1 = 1;

    CarrierServiceBindHelper mCarrierServiceBindHelper;
    @Before
    public void setUp() throws Exception {
@@ -90,4 +99,38 @@ public class CarrierServiceBindHelperTest extends TelephonyTest {
                        CarrierServiceBindHelper.EVENT_PERFORM_IMMEDIATE_UNBIND,
                        new Integer(0)));
    }

    @Test
    public void testCarrierPrivilegesCallbackRegistration() {
        // Device starts with DSDS mode
        doReturn(2).when(mTelephonyManager).getActiveModemCount();
        mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext);
        processAllMessages();

        // Verify that CarrierPrivilegesCallbacks are registered on both phones.
        // Capture the callbacks for further verification
        ArgumentCaptor<CarrierPrivilegesCallback> phone0CallbackCaptor = ArgumentCaptor.forClass(
                CarrierPrivilegesCallback.class);
        verify(mTelephonyManager).registerCarrierPrivilegesCallback(eq(PHONE_ID_0), any(),
                phone0CallbackCaptor.capture());
        CarrierPrivilegesCallback phone0Callback = phone0CallbackCaptor.getAllValues().get(0);
        assertNotNull(phone0Callback);

        ArgumentCaptor<CarrierPrivilegesCallback> phone1CallbackCaptor = ArgumentCaptor.forClass(
                CarrierPrivilegesCallback.class);
        verify(mTelephonyManager).registerCarrierPrivilegesCallback(eq(PHONE_ID_1), any(),
                phone1CallbackCaptor.capture());
        CarrierPrivilegesCallback phone1Callback = phone1CallbackCaptor.getAllValues().get(0);
        assertNotNull(phone1Callback);

        // Switch back to single SIM.
        doReturn(1).when(mTelephonyManager).getActiveModemCount();
        PhoneConfigurationManager.notifyMultiSimConfigChange(1);
        processAllMessages();

        // Verify the callback for phone1 had been unregistered while phone0 didn't.
        verify(mTelephonyManager).unregisterCarrierPrivilegesCallback(eq(phone1Callback));
        verify(mTelephonyManager, never()).unregisterCarrierPrivilegesCallback(eq(phone0Callback));
    }
    // TODO (b/232461097): Add UT cases to cover more scenarios (user unlock, SIM state change...)
}