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

Commit ed7a6169 authored by Nishant Kumar Singh's avatar Nishant Kumar Singh
Browse files

Replace PackageManagerInternal with PackageManager.

PackageManagerInternal in LocaleManagerService allowed any app to query
for another app's existence by looking at the exception message thrown
by the LocaleManager's get/set APIs. External PM, on the other hand,
does package visibility filtering which restricts regular apps from
querying information about other apps.

Bug: 225881167
Bug: 226900861

Test: atest CtsLocaleManagerTestCases
Test: atest CtsLocaleManagerHostTestCases
Test: atest CtsBackupTestCases:AppLocalesBackupTest
Test: atest LocaleManagerServiceTest
Test: atest LocaleManagerBackupRestoreTest
Test: atest SystemAppUpdateTrackerTest
Test: Manually tested by flashing and verifying that the test app
(PocProject) attached in the bug is not able to query app existence, and
also verifying that Settings and PlayStore are able to get/set any app's
locales. Also tested multi-user and work profiles.

Change-Id: If00016e7afd7f6552b6c66984cc0194d1bc449b1
parent 39921c5b
Loading
Loading
Loading
Loading
+7 −9
Original line number Diff line number Diff line
@@ -30,8 +30,6 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.LocaleList;
import android.os.RemoteException;
@@ -78,7 +76,7 @@ class LocaleManagerBackupHelper {
    private static final Duration STAGE_DATA_RETENTION_PERIOD = Duration.ofDays(3);

    private final LocaleManagerService mLocaleManagerService;
    private final PackageManagerInternal mPackageManagerInternal;
    private final PackageManager mPackageManager;
    private final Clock mClock;
    private final Context mContext;
    private final Object mStagedDataLock = new Object();
@@ -90,18 +88,18 @@ class LocaleManagerBackupHelper {
    private final BroadcastReceiver mUserMonitor;

    LocaleManagerBackupHelper(LocaleManagerService localeManagerService,
            PackageManagerInternal pmInternal, HandlerThread broadcastHandlerThread) {
        this(localeManagerService.mContext, localeManagerService, pmInternal, Clock.systemUTC(),
            PackageManager packageManager, HandlerThread broadcastHandlerThread) {
        this(localeManagerService.mContext, localeManagerService, packageManager, Clock.systemUTC(),
                new SparseArray<>(), broadcastHandlerThread);
    }

    @VisibleForTesting LocaleManagerBackupHelper(Context context,
            LocaleManagerService localeManagerService,
            PackageManagerInternal pmInternal, Clock clock, SparseArray<StagedData> stagedData,
            PackageManager packageManager, Clock clock, SparseArray<StagedData> stagedData,
            HandlerThread broadcastHandlerThread) {
        mContext = context;
        mLocaleManagerService = localeManagerService;
        mPackageManagerInternal = pmInternal;
        mPackageManager = packageManager;
        mClock = clock;
        mStagedData = stagedData;

@@ -130,8 +128,8 @@ class LocaleManagerBackupHelper {
        }

        HashMap<String, String> pkgStates = new HashMap<>();
        for (ApplicationInfo appInfo : mPackageManagerInternal.getInstalledApplications(/*flags*/0,
                userId, Binder.getCallingUid())) {
        for (ApplicationInfo appInfo : mPackageManager.getInstalledApplicationsAsUser(
                PackageManager.ApplicationInfoFlags.of(0), userId)) {
            try {
                LocaleList appLocales = mLocaleManagerService.getApplicationLocales(
                        appInfo.packageName,
+12 −8
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ import android.app.ILocaleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.HandlerThread;
@@ -60,7 +60,7 @@ public class LocaleManagerService extends SystemService {
    private final LocaleManagerService.LocaleManagerBinderService mBinderService;
    private ActivityTaskManagerInternal mActivityTaskManagerInternal;
    private ActivityManagerInternal mActivityManagerInternal;
    private PackageManagerInternal mPackageManagerInternal;
    private PackageManager mPackageManager;

    private LocaleManagerBackupHelper mBackupHelper;

@@ -74,7 +74,7 @@ public class LocaleManagerService extends SystemService {
        mBinderService = new LocaleManagerBinderService();
        mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
        mPackageManager = mContext.getPackageManager();

        HandlerThread broadcastHandlerThread = new HandlerThread(TAG,
                Process.THREAD_PRIORITY_BACKGROUND);
@@ -90,7 +90,7 @@ public class LocaleManagerService extends SystemService {
        });

        mBackupHelper = new LocaleManagerBackupHelper(this,
                mPackageManagerInternal, broadcastHandlerThread);
                mPackageManager, broadcastHandlerThread);

        mPackageMonitor = new LocaleManagerServicePackageMonitor(mBackupHelper,
                systemAppUpdateTracker);
@@ -102,7 +102,7 @@ public class LocaleManagerService extends SystemService {
    @VisibleForTesting
    LocaleManagerService(Context context, ActivityTaskManagerInternal activityTaskManagerInternal,
            ActivityManagerInternal activityManagerInternal,
            PackageManagerInternal packageManagerInternal,
            PackageManager packageManager,
            LocaleManagerBackupHelper localeManagerBackupHelper,
            PackageMonitor packageMonitor) {
        super(context);
@@ -110,7 +110,7 @@ public class LocaleManagerService extends SystemService {
        mBinderService = new LocaleManagerBinderService();
        mActivityTaskManagerInternal = activityTaskManagerInternal;
        mActivityManagerInternal = activityManagerInternal;
        mPackageManagerInternal = packageManagerInternal;
        mPackageManager = packageManager;
        mBackupHelper = localeManagerBackupHelper;
        mPackageMonitor = packageMonitor;
    }
@@ -419,8 +419,12 @@ public class LocaleManagerService extends SystemService {
    }

    private int getPackageUid(String appPackageName, int userId) {
        return mPackageManagerInternal
                .getPackageUid(appPackageName, /* flags */ 0, userId);
        try {
            return mPackageManager
                    .getPackageUidAsUser(appPackageName, PackageInfoFlags.of(0), userId);
        } catch (PackageManager.NameNotFoundException e) {
            return Process.INVALID_UID;
        }
    }

    @Nullable
+13 −18
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@@ -39,7 +38,6 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.LocaleList;
@@ -102,8 +100,6 @@ public class LocaleManagerBackupRestoreTest {
    @Mock
    private Context mMockContext;
    @Mock
    private PackageManagerInternal mMockPackageManagerInternal;
    @Mock
    private PackageManager mMockPackageManager;
    @Mock
    private LocaleManagerService mMockLocaleManagerService;
@@ -129,7 +125,6 @@ public class LocaleManagerBackupRestoreTest {
    @Before
    public void setUp() throws Exception {
        mMockContext = mock(Context.class);
        mMockPackageManagerInternal = mock(PackageManagerInternal.class);
        mMockPackageManager = mock(PackageManager.class);
        mMockLocaleManagerService = mock(LocaleManagerService.class);
        SystemAppUpdateTracker systemAppUpdateTracker = mock(SystemAppUpdateTracker.class);
@@ -141,7 +136,7 @@ public class LocaleManagerBackupRestoreTest {
        broadcastHandlerThread.start();

        mBackupHelper = spy(new ShadowLocaleManagerBackupHelper(mMockContext,
                mMockLocaleManagerService, mMockPackageManagerInternal, mClock, STAGE_DATA,
                mMockLocaleManagerService, mMockPackageManager, mClock, STAGE_DATA,
                broadcastHandlerThread));
        doNothing().when(mBackupHelper).notifyBackupManager();

@@ -158,8 +153,8 @@ public class LocaleManagerBackupRestoreTest {

    @Test
    public void testBackupPayload_noAppsInstalled_returnsNull() throws Exception {
        doReturn(List.of()).when(mMockPackageManagerInternal)
                .getInstalledApplications(anyLong(), anyInt(), anyInt());
        doReturn(List.of()).when(mMockPackageManager)
                .getInstalledApplicationsAsUser(any(), anyInt());

        assertNull(mBackupHelper.getBackupPayload(DEFAULT_USER_ID));
    }
@@ -198,8 +193,8 @@ public class LocaleManagerBackupRestoreTest {
        ApplicationInfo anotherAppInfo = new ApplicationInfo();
        defaultAppInfo.packageName = DEFAULT_PACKAGE_NAME;
        anotherAppInfo.packageName = "com.android.anotherapp";
        doReturn(List.of(defaultAppInfo, anotherAppInfo)).when(mMockPackageManagerInternal)
                .getInstalledApplications(anyLong(), anyInt(), anyInt());
        doReturn(List.of(defaultAppInfo, anotherAppInfo)).when(mMockPackageManager)
                .getInstalledApplicationsAsUser(any(), anyInt());

        setUpLocalesForPackage(DEFAULT_PACKAGE_NAME, DEFAULT_LOCALES);
        // Exception when getting locales for anotherApp.
@@ -447,8 +442,8 @@ public class LocaleManagerBackupRestoreTest {
        // Retention period has not elapsed.
        setCurrentTimeMillis(
                DEFAULT_CREATION_TIME_MILLIS + RETENTION_PERIOD.minusHours(1).toMillis());
        doReturn(List.of()).when(mMockPackageManagerInternal)
                .getInstalledApplications(anyLong(), anyInt(), anyInt());
        doReturn(List.of()).when(mMockPackageManager)
                .getInstalledApplicationsAsUser(any(), anyInt());
        assertNull(mBackupHelper.getBackupPayload(DEFAULT_USER_ID));

        checkStageDataExists(DEFAULT_USER_ID);
@@ -456,8 +451,8 @@ public class LocaleManagerBackupRestoreTest {
        // Exactly RETENTION_PERIOD amount of time has passed so stage data should still not be
        // removed.
        setCurrentTimeMillis(DEFAULT_CREATION_TIME_MILLIS + RETENTION_PERIOD.toMillis());
        doReturn(List.of()).when(mMockPackageManagerInternal)
                .getInstalledApplications(anyLong(), anyInt(), anyInt());
        doReturn(List.of()).when(mMockPackageManager)
                .getInstalledApplicationsAsUser(any(), anyInt());
        assertNull(mBackupHelper.getBackupPayload(DEFAULT_USER_ID));

        checkStageDataExists(DEFAULT_USER_ID);
@@ -465,8 +460,8 @@ public class LocaleManagerBackupRestoreTest {
        // Retention period has now expired, stage data should be deleted.
        setCurrentTimeMillis(
                DEFAULT_CREATION_TIME_MILLIS + RETENTION_PERIOD.plusSeconds(1).toMillis());
        doReturn(List.of()).when(mMockPackageManagerInternal)
                .getInstalledApplications(anyLong(), anyInt(), anyInt());
        doReturn(List.of()).when(mMockPackageManager)
                .getInstalledApplicationsAsUser(any(), anyInt());
        assertNull(mBackupHelper.getBackupPayload(DEFAULT_USER_ID));

        checkStageDataDoesNotExist(DEFAULT_USER_ID);
@@ -577,8 +572,8 @@ public class LocaleManagerBackupRestoreTest {
    private void setUpDummyAppForPackageManager(String packageName) {
        ApplicationInfo dummyApp = new ApplicationInfo();
        dummyApp.packageName = packageName;
        doReturn(List.of(dummyApp)).when(mMockPackageManagerInternal)
                .getInstalledApplications(anyLong(), anyInt(), anyInt());
        doReturn(List.of(dummyApp)).when(mMockPackageManager)
                .getInstalledApplicationsAsUser(any(), anyInt());
    }

    /**
+24 −27
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import static junit.framework.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
@@ -40,7 +39,6 @@ import android.content.Context;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.LocaleList;

@@ -80,7 +78,7 @@ public class LocaleManagerServiceTest {
    @Mock
    private Context mMockContext;
    @Mock
    private PackageManagerInternal mMockPackageManagerInternal;
    private PackageManager mMockPackageManager;
    @Mock
    private FakePackageConfigurationUpdater mFakePackageConfigurationUpdater;
    @Mock
@@ -95,14 +93,13 @@ public class LocaleManagerServiceTest {
        mMockContext = mock(Context.class);
        mMockActivityTaskManager = mock(ActivityTaskManagerInternal.class);
        mMockActivityManager = mock(ActivityManagerInternal.class);
        mMockPackageManagerInternal = mock(PackageManagerInternal.class);
        mMockPackageManager = mock(PackageManager.class);
        mMockPackageMonitor = mock(PackageMonitor.class);

        // For unit tests, set the default installer info
        PackageManager mockPackageManager = mock(PackageManager.class);
        doReturn(DEFAULT_INSTALL_SOURCE_INFO).when(mockPackageManager)
        doReturn(DEFAULT_INSTALL_SOURCE_INFO).when(mMockPackageManager)
                .getInstallSourceInfo(anyString());
        doReturn(mockPackageManager).when(mMockContext).getPackageManager();
        doReturn(mMockPackageManager).when(mMockContext).getPackageManager();

        mFakePackageConfigurationUpdater = new FakePackageConfigurationUpdater();
        doReturn(mFakePackageConfigurationUpdater)
@@ -117,14 +114,14 @@ public class LocaleManagerServiceTest {

        mMockBackupHelper = mock(ShadowLocaleManagerBackupHelper.class);
        mLocaleManagerService = new LocaleManagerService(mMockContext, mMockActivityTaskManager,
                mMockActivityManager, mMockPackageManagerInternal,
                mMockActivityManager, mMockPackageManager,
                mMockBackupHelper, mMockPackageMonitor);
    }

    @Test(expected = SecurityException.class)
    public void testSetApplicationLocales_arbitraryAppWithoutPermissions_fails() throws Exception {
        doReturn(DEFAULT_UID)
                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyLong(), anyInt());
                .when(mMockPackageManager).getPackageUidAsUser(anyString(), any(), anyInt());
        setUpFailingPermissionCheckFor(Manifest.permission.CHANGE_CONFIGURATION);

        try {
@@ -170,7 +167,7 @@ public class LocaleManagerServiceTest {
    @Test
    public void testSetApplicationLocales_arbitraryAppWithPermission_succeeds() throws Exception {
        doReturn(DEFAULT_UID)
                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyLong(), anyInt());
                .when(mMockPackageManager).getPackageUidAsUser(anyString(), any(), anyInt());
        // if package is not owned by the caller, the calling app should have the following
        //   permission. We will mock this to succeed to imitate that.
        setUpPassingPermissionCheckFor(Manifest.permission.CHANGE_CONFIGURATION);
@@ -186,7 +183,7 @@ public class LocaleManagerServiceTest {
    @Test
    public void testSetApplicationLocales_callerOwnsPackage_succeeds() throws Exception {
        doReturn(Binder.getCallingUid())
                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyLong(), anyInt());
                .when(mMockPackageManager).getPackageUidAsUser(anyString(), any(), anyInt());

        mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID,
                DEFAULT_LOCALES);
@@ -197,8 +194,8 @@ public class LocaleManagerServiceTest {

    @Test(expected = IllegalArgumentException.class)
    public void testSetApplicationLocales_invalidPackageOrUserId_fails() throws Exception {
        doReturn(INVALID_UID)
                .when(mMockPackageManagerInternal).getPackageUid(anyString(), anyLong(), anyInt());
        doThrow(new PackageManager.NameNotFoundException("Mock"))
                .when(mMockPackageManager).getPackageUidAsUser(anyString(), any(), anyInt());
        try {
            mLocaleManagerService.setApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID,
                    LocaleList.getEmptyLocaleList());
@@ -211,8 +208,8 @@ public class LocaleManagerServiceTest {

    @Test(expected = SecurityException.class)
    public void testGetApplicationLocales_arbitraryAppWithoutPermission_fails() throws Exception {
        doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
                .getPackageUid(anyString(), anyLong(), anyInt());
        doReturn(DEFAULT_UID).when(mMockPackageManager)
                .getPackageUidAsUser(anyString(), any(), anyInt());
        setUpFailingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);

        try {
@@ -229,8 +226,8 @@ public class LocaleManagerServiceTest {
    public void testGetApplicationLocales_appSpecificConfigAbsent_returnsEmptyList()
            throws Exception {
        // any valid app calling for its own package or having appropriate permission
        doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
                .getPackageUid(anyString(), anyLong(), anyInt());
        doReturn(DEFAULT_UID).when(mMockPackageManager)
                .getPackageUidAsUser(anyString(), any(), anyInt());
        setUpPassingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);
        doReturn(null)
                .when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
@@ -244,8 +241,8 @@ public class LocaleManagerServiceTest {
    @Test
    public void testGetApplicationLocales_appSpecificLocalesAbsent_returnsEmptyList()
            throws Exception {
        doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
                .getPackageUid(anyString(), anyLong(), anyInt());
        doReturn(DEFAULT_UID).when(mMockPackageManager)
                .getPackageUidAsUser(anyString(), any(), anyInt());
        setUpPassingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);
        doReturn(new PackageConfig(/* nightMode = */ 0, /* locales = */ null))
                .when(mMockActivityTaskManager).getApplicationConfig(any(), anyInt());
@@ -259,8 +256,8 @@ public class LocaleManagerServiceTest {
    @Test
    public void testGetApplicationLocales_callerOwnsAppAndConfigPresent_returnsLocales()
            throws Exception {
        doReturn(Binder.getCallingUid()).when(mMockPackageManagerInternal)
                .getPackageUid(anyString(), anyLong(), anyInt());
        doReturn(Binder.getCallingUid()).when(mMockPackageManager)
                .getPackageUidAsUser(anyString(), any(), anyInt());
        doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
                .when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());

@@ -273,8 +270,8 @@ public class LocaleManagerServiceTest {
    @Test
    public void testGetApplicationLocales_arbitraryCallerWithPermissions_returnsLocales()
            throws Exception {
        doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
                .getPackageUid(anyString(), anyLong(), anyInt());
        doReturn(DEFAULT_UID).when(mMockPackageManager)
                .getPackageUidAsUser(anyString(), any(), anyInt());
        setUpPassingPermissionCheckFor(Manifest.permission.READ_APP_SPECIFIC_LOCALES);
        doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
                .when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
@@ -288,10 +285,10 @@ public class LocaleManagerServiceTest {
    @Test
    public void testGetApplicationLocales_callerIsInstaller_returnsLocales()
            throws Exception {
        doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
                .getPackageUid(eq(DEFAULT_PACKAGE_NAME), anyLong(), anyInt());
        doReturn(Binder.getCallingUid()).when(mMockPackageManagerInternal)
                .getPackageUid(eq(DEFAULT_INSTALLER_PACKAGE_NAME), anyLong(), anyInt());
        doReturn(DEFAULT_UID).when(mMockPackageManager)
                .getPackageUidAsUser(eq(DEFAULT_PACKAGE_NAME), any(), anyInt());
        doReturn(Binder.getCallingUid()).when(mMockPackageManager)
                .getPackageUidAsUser(eq(DEFAULT_INSTALLER_PACKAGE_NAME), any(), anyInt());
        doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
                .when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());

+4 −3
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@
package com.android.server.locales;

import android.content.Context;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManager;
import android.os.HandlerThread;
import android.util.SparseArray;

@@ -31,9 +31,10 @@ import java.time.Clock;
public class ShadowLocaleManagerBackupHelper extends LocaleManagerBackupHelper {
    ShadowLocaleManagerBackupHelper(Context context,
            LocaleManagerService localeManagerService,
            PackageManagerInternal pmInternal, Clock clock,
            PackageManager packageManager, Clock clock,
            SparseArray<LocaleManagerBackupHelper.StagedData> stagedData,
            HandlerThread broadcastHandlerThread) {
        super(context, localeManagerService, pmInternal, clock, stagedData, broadcastHandlerThread);
        super(context, localeManagerService, packageManager, clock, stagedData,
                broadcastHandlerThread);
    }
}
Loading