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

Commit 6777a92c authored by Rambo Wang's avatar Rambo Wang
Browse files

Optimize getCarrierServicePackageName in CarrierPrivilegesTracker

The original implementation will always query package manager
which is pretty heavy operation and prone to deadlock.

This CL optimizes the method with paths below:
- Return cache if present
- Perform light query on install packages for services only
- Perform original heavy query as before as the last resort

In majority of the cases, the cache is returned and this should
largely improve the performance of the method and reduce the
risk for deadlock or IPC thread blocking.

Bug: 217442920
Test: atest CarrierPrivilegesTrackerTest
Change-Id: I2163fac6c371a706e565050ea6ad066cbca8f588
Merged-In: I2163fac6c371a706e565050ea6ad066cbca8f588
(cherry picked from commit bcf5d849)
parent 89dabb58
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -932,6 +932,41 @@ public class CarrierPrivilegesTracker extends Handler {
        }
    }

    /**
     * Backing of {@link TelephonyManager#getCarrierServicePackageName()} and
     * {@link TelephonyManager#getCarrierServicePackageNameForLogicalSlot(int)}
     */
    @Nullable
    public String getCarrierServicePackageName() {
        // Return the cached one if present, it is fast and safe (no IPC call to PackageManager)
        mPrivilegedPackageInfoLock.readLock().lock();
        try {
            // If SIM is READY but not LOADED, neither the cache nor the queries below are reliable,
            // we should return null for this transient state for security/privacy's concern.
            if (mSimIsReadyButNotLoaded) return null;

            return mPrivilegedPackageInfo.mCarrierService.first;
        } finally {
            mPrivilegedPackageInfoLock.readLock().unlock();
        }
        // Do NOT query package manager, mPrivilegedPackageInfo.mCarrierService has maintained the
        // latest CarrierService info. Querying PM will not get better result.
    }

    /**
     * @return The UID of carrier service package. {@link Process#INVALID_UID} if not found.
     */
    public int getCarrierServicePackageUid() {
        mPrivilegedPackageInfoLock.readLock().lock();
        try {
            if (mSimIsReadyButNotLoaded) return Process.INVALID_UID;

            return mPrivilegedPackageInfo.mCarrierService.second;
        } finally {
            mPrivilegedPackageInfoLock.readLock().unlock();
        }
    }

    /**
     * Backing of {@link TelephonyManager#getCarrierPackageNamesForIntent} and {@link
     * TelephonyManager#getCarrierPackageNamesForIntentAndPhone}.
+101 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import static android.telephony.TelephonyManager.SIM_STATE_READY;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
@@ -59,6 +60,7 @@ import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.Process;
import android.service.carrier.CarrierService;
import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
@@ -966,6 +968,105 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest {
                new HashSet<>(carrierPackageNames));
    }

    @Test
    public void testGetCarrierService_haveCarrierServiceWithCarrierPrivileges() throws Exception {
        // Only packages with CERT_1 have carrier privileges
        setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1)));
        // Setup all odd packages privileged, even packages not
        setupInstalledPackages(
                new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1),
                new PackageCertInfo(PACKAGE_2, CERT_2, USER_1, UID_2),
                new PackageCertInfo(PACKAGE_3, CERT_1, USER_1, UID_1));
        // Two declared CarrierService, only PACKAGE_1 has carrier privileges
        ResolveInfo privilegeService = new ResolveInfoBuilder().setService(PACKAGE_1).build();
        ResolveInfo noPrivilegeService = new ResolveInfoBuilder().setService(PACKAGE_2).build();
        // Use doReturn instead of when/thenReturn which has NPE with unknown reason
        doReturn(List.of(privilegeService, noPrivilegeService)).when(
                mPackageManager).queryIntentServices(any(), anyInt());
        when(mPackageManager.getPackageUid(eq(PACKAGE_1), anyInt())).thenReturn(UID_1);
        when(mPackageManager.getPackageUid(eq(PACKAGE_2), anyInt())).thenReturn(UID_2);
        when(mPackageManager.getPackageUid(eq(PACKAGE_3), anyInt())).thenReturn(UID_1);

        // Get CS package name for the first time
        mCarrierPrivilegesTracker = createCarrierPrivilegesTracker();
        String carrierServicePackageName = mCarrierPrivilegesTracker.getCarrierServicePackageName();
        int carrierServiceUid = mCarrierPrivilegesTracker.getCarrierServicePackageUid();
        mTestableLooper.processAllMessages();

        // Package manager should be queried from
        verify(mPackageManager).queryIntentServices(any(), anyInt());
        assertEquals(PACKAGE_1, carrierServicePackageName);
        assertEquals(UID_1, carrierServiceUid);


        reset(mPackageManager);
        // Get CS again
        carrierServicePackageName = mCarrierPrivilegesTracker.getCarrierServicePackageName();
        carrierServiceUid = mCarrierPrivilegesTracker.getCarrierServicePackageUid();
        mTestableLooper.processAllMessages();

        // It should return the same result, but didn't query package manager
        verify(mPackageManager, never()).queryIntentServices(any(), anyInt());
        assertEquals(PACKAGE_1, carrierServicePackageName);
        assertEquals(UID_1, carrierServiceUid);

    }

    @Test
    public void testGetCarrierService_haveCarrierServiceWithNoCarrierPrivileges() throws Exception {
        // Only packages with CERT_1 have carrier privileges
        setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1)));
        // Setup all odd packages privileged, even packages not
        setupInstalledPackages(
                new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1),
                new PackageCertInfo(PACKAGE_2, CERT_2, USER_1, UID_2),
                new PackageCertInfo(PACKAGE_3, CERT_1, USER_1, UID_1));
        // One declared CarrierService which has no carrier privileges
        ResolveInfo noPrivilegeService = new ResolveInfoBuilder().setService(PACKAGE_2).build();
        // Use doReturn instead of when/thenReturn which has NPE with unknown reason
        doReturn(List.of(noPrivilegeService)).when(
                mPackageManager).queryIntentServices(any(), anyInt());
        when(mPackageManager.getPackageUid(eq(PACKAGE_1), anyInt())).thenReturn(UID_1);
        when(mPackageManager.getPackageUid(eq(PACKAGE_2), anyInt())).thenReturn(UID_2);
        when(mPackageManager.getPackageUid(eq(PACKAGE_3), anyInt())).thenReturn(UID_1);

        mCarrierPrivilegesTracker = createCarrierPrivilegesTracker();
        String carrierServicePackageName = mCarrierPrivilegesTracker.getCarrierServicePackageName();
        int carrierServiceUid = mCarrierPrivilegesTracker.getCarrierServicePackageUid();
        mTestableLooper.processAllMessages();

        verify(mPackageManager).queryIntentServices(any(), anyInt());
        assertNull(carrierServicePackageName);
        assertEquals(Process.INVALID_UID, carrierServiceUid);
    }

    @Test
    public void testGetCarrierService_haveNoCarrierService() throws Exception {
        // Only packages with CERT_1 have carrier privileges
        setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1)));
        // Setup all odd packages privileged, even packages not
        setupInstalledPackages(
                new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1),
                new PackageCertInfo(PACKAGE_2, CERT_2, USER_1, UID_2),
                new PackageCertInfo(PACKAGE_3, CERT_1, USER_1, UID_1));
        // No CarrierService declared at all
        // Use doReturn instead of when/thenReturn which has NPE with unknown reason
        doReturn(List.of()).when(
                mPackageManager).queryIntentServices(any(), anyInt());
        when(mPackageManager.getPackageUid(eq(PACKAGE_1), anyInt())).thenReturn(UID_1);
        when(mPackageManager.getPackageUid(eq(PACKAGE_2), anyInt())).thenReturn(UID_2);
        when(mPackageManager.getPackageUid(eq(PACKAGE_3), anyInt())).thenReturn(UID_1);

        mCarrierPrivilegesTracker = createCarrierPrivilegesTracker();
        String carrierServicePackageName = mCarrierPrivilegesTracker.getCarrierServicePackageName();
        int carrierServiceUid = mCarrierPrivilegesTracker.getCarrierServicePackageUid();
        mTestableLooper.processAllMessages();

        assertNull(carrierServicePackageName);
        assertEquals(Process.INVALID_UID, carrierServiceUid);
        verify(mPackageManager).queryIntentServices(any(), anyInt());
    }

    private void sendCarrierConfigChangedIntent(int subId, int phoneId) {
        mContext.sendBroadcast(
                new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)