Loading services/core/java/com/android/server/am/AppRestrictionController.java +65 −32 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ import android.provider.DeviceConfig.OnPropertiesChangedListener; import android.provider.DeviceConfig.Properties; import android.provider.Settings; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.text.TextUtils; import android.util.ArraySet; import android.util.AtomicFile; Loading Loading @@ -312,10 +313,18 @@ public final class AppRestrictionController { private final Object mCarrierPrivilegedLock = new Object(); /** * List of carrier-privileged apps that should be excluded from standby. * List of carrier-privileged apps that should be excluded from standby, * the key of this array here is the phone id. */ @GuardedBy("mCarrierPrivilegedLock") private List<String> mCarrierPrivilegedApps; private final SparseArray<Set<String>> mCarrierPrivilegedApps = new SparseArray<>(); /** * Holding the callbacks to the carrier privileged app changes. * * it's lock free. */ private volatile ArrayList<PhoneCarrierPrivilegesCallback> mCarrierPrivilegesCallbacks; /** * Whether or not we've loaded the restriction settings from the persistent storage. Loading Loading @@ -358,19 +367,6 @@ public final class AppRestrictionController { onUidAdded(uid); } } } // fall through. case Intent.ACTION_PACKAGE_CHANGED: { final String pkgName = intent.getData().getSchemeSpecificPart(); final String[] cmpList = intent.getStringArrayExtra( Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); // If this is PACKAGE_ADDED (cmpList == null), or if it's a whole-package // enable/disable event (cmpList is just the package name itself), drop // our carrier privileged app & system-app caches and let them refresh if (cmpList == null || (cmpList.length == 1 && pkgName.equals(cmpList[0]))) { clearCarrierPrivilegedApps(); } } break; case Intent.ACTION_PACKAGE_FULLY_REMOVED: { final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); Loading Loading @@ -413,6 +409,10 @@ public final class AppRestrictionController { onUserRemoved(userId); } } break; case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED: { unregisterCarrierPrivilegesCallbacks(); registerCarrierPrivilegesCallbacks(); } break; } } }; Loading Loading @@ -1501,6 +1501,7 @@ public final class AppRestrictionController { initRolesInInterest(); registerForUidObservers(); registerForSystemBroadcasts(); registerCarrierPrivilegesCallbacks(); mNotificationHelper.onSystemReady(); mInjector.getAppStateTracker().addBackgroundRestrictedAppListener( mBackgroundRestrictionListener); Loading Loading @@ -2816,6 +2817,7 @@ public final class AppRestrictionController { final PackageManagerInternal pm = mInjector.getPackageManagerInternal(); final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal(); final AppOpsManager appOpsManager = mInjector.getAppOpsManager(); final ActivityManagerService activityManagerService = mInjector.getActivityManagerService(); final int userId = UserHandle.getUserId(uid); if (isSystemModule(pkg)) { return REASON_SYSTEM_MODULE; Loading @@ -2829,7 +2831,7 @@ public final class AppRestrictionController { return REASON_DPO_PROTECTED_APP; } else if (appStandbyInternal.isActiveDeviceAdmin(pkg, userId)) { return REASON_ACTIVE_DEVICE_ADMIN; } else if (mActivityManagerService.mConstants.mFlagSystemExemptPowerRestrictionsEnabled } else if (activityManagerService.mConstants.mFlagSystemExemptPowerRestrictionsEnabled && appOpsManager.checkOpNoThrow( AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, uid, pkg) == AppOpsManager.MODE_ALLOWED) { Loading Loading @@ -2872,32 +2874,61 @@ public final class AppRestrictionController { private boolean isCarrierApp(String packageName) { synchronized (mCarrierPrivilegedLock) { if (mCarrierPrivilegedApps == null) { fetchCarrierPrivilegedAppsCPL(); } if (mCarrierPrivilegedApps != null) { return mCarrierPrivilegedApps.contains(packageName); for (int i = mCarrierPrivilegedApps.size() - 1; i >= 0; i--) { if (mCarrierPrivilegedApps.valueAt(i).contains(packageName)) { return true; } } } return false; } } private void clearCarrierPrivilegedApps() { if (DEBUG_BG_RESTRICTION_CONTROLLER) { Slog.i(TAG, "Clearing carrier privileged apps list"); private void registerCarrierPrivilegesCallbacks() { final TelephonyManager telephonyManager = mInjector.getTelephonyManager(); if (telephonyManager == null) { return; } synchronized (mCarrierPrivilegedLock) { mCarrierPrivilegedApps = null; // Need to be refetched. final int numPhones = telephonyManager.getActiveModemCount(); final ArrayList<PhoneCarrierPrivilegesCallback> callbacks = new ArrayList<>(); for (int i = 0; i < numPhones; i++) { final PhoneCarrierPrivilegesCallback callback = new PhoneCarrierPrivilegesCallback(i); callbacks.add(callback); telephonyManager.registerCarrierPrivilegesCallback(i, mBgExecutor, callback); } mCarrierPrivilegesCallbacks = callbacks; } @GuardedBy("mCarrierPrivilegedLock") private void fetchCarrierPrivilegedAppsCPL() { private void unregisterCarrierPrivilegesCallbacks() { final TelephonyManager telephonyManager = mInjector.getTelephonyManager(); mCarrierPrivilegedApps = telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions(); if (DEBUG_BG_RESTRICTION_CONTROLLER) { Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps); if (telephonyManager == null) { return; } final ArrayList<PhoneCarrierPrivilegesCallback> callbacks = mCarrierPrivilegesCallbacks; if (callbacks != null) { for (int i = callbacks.size() - 1; i >= 0; i--) { telephonyManager.unregisterCarrierPrivilegesCallback(callbacks.get(i)); } mCarrierPrivilegesCallbacks = null; } } private class PhoneCarrierPrivilegesCallback implements CarrierPrivilegesCallback { private final int mPhoneId; PhoneCarrierPrivilegesCallback(int phoneId) { mPhoneId = phoneId; } @Override public void onCarrierPrivilegesChanged(@NonNull Set<String> privilegedPackageNames, @NonNull Set<Integer> privilegedUids) { synchronized (mCarrierPrivilegedLock) { mCarrierPrivilegedApps.put(mPhoneId, Collections.unmodifiableSet(privilegedPackageNames)); } } } Loading Loading @@ -3265,7 +3296,6 @@ public final class AppRestrictionController { private void registerForSystemBroadcasts() { final IntentFilter packageFilter = new IntentFilter(); packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); packageFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); packageFilter.addDataScheme("package"); mContext.registerReceiverForAllUsers(mBroadcastReceiver, packageFilter, null, mBgHandler); Loading @@ -3278,6 +3308,9 @@ public final class AppRestrictionController { bootFilter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED); mContext.registerReceiverAsUser(mBootReceiver, UserHandle.SYSTEM, bootFilter, null, mBgHandler); final IntentFilter telFilter = new IntentFilter( TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED); mContext.registerReceiverForAllUsers(mBroadcastReceiver, telFilter, null, mBgHandler); } private void unregisterForSystemBroadcasts() { Loading services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java +165 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,8 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; import static android.os.PowerExemptionManager.REASON_CARRIER_PRIVILEGED_APP; import static android.os.PowerExemptionManager.REASON_DENIED; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; Loading Loading @@ -90,6 +92,7 @@ import static org.mockito.Mockito.anyObject; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; Loading Loading @@ -132,8 +135,10 @@ import android.permission.PermissionManager; import android.provider.DeviceConfig; import android.service.notification.StatusBarNotification; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import androidx.test.runner.AndroidJUnit4; Loading Loading @@ -176,9 +181,12 @@ import java.io.File; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.BiConsumer; Loading Loading @@ -233,8 +241,42 @@ public final class BackgroundRestrictionTest { private static final int BATTERY_FULL_CHARGE_MAH = 5_000; private static final String[] MOCK_PRIVILEGED_PACKAGES_0 = new String[] { TEST_PACKAGE_BASE + 0, TEST_PACKAGE_BASE + 1, }; private static final String[] MOCK_PRIVILEGED_PACKAGES_1 = new String[] { TEST_PACKAGE_BASE + 2, TEST_PACKAGE_BASE + 3, }; private static final String[] MOCK_PRIVILEGED_PACKAGES_2 = new String[] { TEST_PACKAGE_BASE + 4, TEST_PACKAGE_BASE + 5, }; private static final int[] MOCK_PRIVILEGED_UIDS_0 = new int[] { UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 0), UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 1), }; private static final int[] MOCK_PRIVILEGED_UIDS_1 = new int[] { UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 2), UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 3), }; private static final int[] MOCK_PRIVILEGED_UIDS_2 = new int[] { UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 4), UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 5), }; private static final String[][] MOCK_PRIVILEGED_PACKAGES = new String[][] { MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_PACKAGES_1, }; private static final int[][] MOCK_PRIVILEGED_UIDS = new int[][] { MOCK_PRIVILEGED_UIDS_0, MOCK_PRIVILEGED_UIDS_1, }; @Mock private ActivityManagerInternal mActivityManagerInternal; @Mock private ActivityManagerService mActivityManagerService; @Mock private ActivityManagerConstants mActivityManagerConstants; @Mock private AppOpsManager mAppOpsManager; @Mock private AppStandbyInternal mAppStandbyInternal; @Mock private AppHibernationManagerInternal mAppHibernationInternal; Loading @@ -255,6 +297,8 @@ public final class BackgroundRestrictionTest { @Mock private TelephonyManager mTelephonyManager; @Mock private IAppOpsService mIAppOpsService; private PhoneCarrierPrivileges mPhoneCarrierPrivileges; private long mCurrentTimeMillis; @Captor private ArgumentCaptor<AppStateTracker.BackgroundRestrictedAppListener> mFasListenerCap; Loading Loading @@ -298,6 +342,14 @@ public final class BackgroundRestrictionTest { mBgRestrictionController = spy(new AppRestrictionController(mInjector, mActivityManagerService)); mActivityManagerService.mConstants = mActivityManagerConstants; mPhoneCarrierPrivileges = new PhoneCarrierPrivileges( mInjector.getTelephonyManager(), MOCK_PRIVILEGED_PACKAGES.length); for (int i = 0; i < MOCK_PRIVILEGED_PACKAGES.length; i++) { mPhoneCarrierPrivileges.addNewPrivilegePackages(i, MOCK_PRIVILEGED_PACKAGES[i], MOCK_PRIVILEGED_UIDS[i]); } doReturn(PROCESS_STATE_FOREGROUND_SERVICE).when(mActivityManagerInternal) .getUidProcessState(anyInt()); doReturn(TEST_USERS).when(mUserManagerInternal).getUserIds(); Loading Loading @@ -2984,6 +3036,78 @@ public final class BackgroundRestrictionTest { verifyLoadedSettings(settings); } @Test public void testCarrierPrivilegedAppListener() throws Exception { final long shortMs = 1_000L; for (int i = 0; i < MOCK_PRIVILEGED_PACKAGES.length; i++) { verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES[i], MOCK_PRIVILEGED_UIDS[i]); } verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); mPhoneCarrierPrivileges.addNewPrivilegePackages(0, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); Thread.sleep(shortMs); verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_UIDS_0); verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES_1, MOCK_PRIVILEGED_UIDS_1); mPhoneCarrierPrivileges.addNewPrivilegePackages(1, new String[0], new int[0]); Thread.sleep(shortMs); verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_UIDS_0); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_1, MOCK_PRIVILEGED_UIDS_1); mPhoneCarrierPrivileges.addNewPrivilegePackages(0, MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_UIDS_0); Thread.sleep(shortMs); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_UIDS_0); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_1, MOCK_PRIVILEGED_UIDS_1); } private void verifyPotentialSystemExemptionReason(int expectedReason, String[] packages, int[] uids) throws Exception { for (int i = 0; i < packages.length; i++) { assertEquals(expectedReason, mBgRestrictionController.getPotentialSystemExemptionReason( uids[i], packages[i])); } } private void verifyLoadedSettings(RestrictionSettings settings) throws Exception { // Make a new copy and reset it. RestrictionSettings test = (RestrictionSettings) settings.clone(); Loading Loading @@ -3019,6 +3143,47 @@ public final class BackgroundRestrictionTest { return result; } private class PhoneCarrierPrivileges { private final SparseArray<Pair<String[], int[]>> mPackages = new SparseArray<>(); private final SparseArray<Pair<Executor, CarrierPrivilegesCallback>> mListeners = new SparseArray<>(); PhoneCarrierPrivileges(TelephonyManager telephonyManager, int phoneIds) { doReturn(phoneIds).when(telephonyManager).getActiveModemCount(); doAnswer(inv -> { registerCarrierPrivilegesCallback( inv.getArgument(0), inv.getArgument(1), inv.getArgument(2)); return null; }).when(telephonyManager).registerCarrierPrivilegesCallback( anyInt(), anyObject(), anyObject()); } public void registerCarrierPrivilegesCallback(int phoneId, Executor executor, CarrierPrivilegesCallback callback) { mListeners.put(phoneId, Pair.create(executor, callback)); final Pair<String[], int[]> pkgs = mPackages.get(phoneId); final Set<String> pkgNames = pkgs != null ? Arrays.stream(pkgs.first).collect(Collectors.toUnmodifiableSet()) : Collections.emptySet(); final Set<Integer> uids = pkgs != null ? Arrays.stream(pkgs.second).boxed().collect(Collectors.toUnmodifiableSet()) : Collections.emptySet(); executor.execute(() -> callback.onCarrierPrivilegesChanged(pkgNames, uids)); } public void addNewPrivilegePackages(int phoneId, String[] pkgNames, int[] uids) { mPackages.put(phoneId, Pair.create(pkgNames, uids)); final Pair<Executor, CarrierPrivilegesCallback> callback = mListeners.get(phoneId); if (callback != null) { callback.first.execute(() -> callback.second.onCarrierPrivilegesChanged( Arrays.stream(pkgNames).collect(Collectors.toUnmodifiableSet()), Arrays.stream(uids).boxed().collect(Collectors.toUnmodifiableSet()))); } } } private class TestBgRestrictionInjector extends AppRestrictionController.Injector { private Context mContext; Loading Loading
services/core/java/com/android/server/am/AppRestrictionController.java +65 −32 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ import android.provider.DeviceConfig.OnPropertiesChangedListener; import android.provider.DeviceConfig.Properties; import android.provider.Settings; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.text.TextUtils; import android.util.ArraySet; import android.util.AtomicFile; Loading Loading @@ -312,10 +313,18 @@ public final class AppRestrictionController { private final Object mCarrierPrivilegedLock = new Object(); /** * List of carrier-privileged apps that should be excluded from standby. * List of carrier-privileged apps that should be excluded from standby, * the key of this array here is the phone id. */ @GuardedBy("mCarrierPrivilegedLock") private List<String> mCarrierPrivilegedApps; private final SparseArray<Set<String>> mCarrierPrivilegedApps = new SparseArray<>(); /** * Holding the callbacks to the carrier privileged app changes. * * it's lock free. */ private volatile ArrayList<PhoneCarrierPrivilegesCallback> mCarrierPrivilegesCallbacks; /** * Whether or not we've loaded the restriction settings from the persistent storage. Loading Loading @@ -358,19 +367,6 @@ public final class AppRestrictionController { onUidAdded(uid); } } } // fall through. case Intent.ACTION_PACKAGE_CHANGED: { final String pkgName = intent.getData().getSchemeSpecificPart(); final String[] cmpList = intent.getStringArrayExtra( Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); // If this is PACKAGE_ADDED (cmpList == null), or if it's a whole-package // enable/disable event (cmpList is just the package name itself), drop // our carrier privileged app & system-app caches and let them refresh if (cmpList == null || (cmpList.length == 1 && pkgName.equals(cmpList[0]))) { clearCarrierPrivilegedApps(); } } break; case Intent.ACTION_PACKAGE_FULLY_REMOVED: { final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); Loading Loading @@ -413,6 +409,10 @@ public final class AppRestrictionController { onUserRemoved(userId); } } break; case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED: { unregisterCarrierPrivilegesCallbacks(); registerCarrierPrivilegesCallbacks(); } break; } } }; Loading Loading @@ -1501,6 +1501,7 @@ public final class AppRestrictionController { initRolesInInterest(); registerForUidObservers(); registerForSystemBroadcasts(); registerCarrierPrivilegesCallbacks(); mNotificationHelper.onSystemReady(); mInjector.getAppStateTracker().addBackgroundRestrictedAppListener( mBackgroundRestrictionListener); Loading Loading @@ -2816,6 +2817,7 @@ public final class AppRestrictionController { final PackageManagerInternal pm = mInjector.getPackageManagerInternal(); final AppStandbyInternal appStandbyInternal = mInjector.getAppStandbyInternal(); final AppOpsManager appOpsManager = mInjector.getAppOpsManager(); final ActivityManagerService activityManagerService = mInjector.getActivityManagerService(); final int userId = UserHandle.getUserId(uid); if (isSystemModule(pkg)) { return REASON_SYSTEM_MODULE; Loading @@ -2829,7 +2831,7 @@ public final class AppRestrictionController { return REASON_DPO_PROTECTED_APP; } else if (appStandbyInternal.isActiveDeviceAdmin(pkg, userId)) { return REASON_ACTIVE_DEVICE_ADMIN; } else if (mActivityManagerService.mConstants.mFlagSystemExemptPowerRestrictionsEnabled } else if (activityManagerService.mConstants.mFlagSystemExemptPowerRestrictionsEnabled && appOpsManager.checkOpNoThrow( AppOpsManager.OP_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS, uid, pkg) == AppOpsManager.MODE_ALLOWED) { Loading Loading @@ -2872,32 +2874,61 @@ public final class AppRestrictionController { private boolean isCarrierApp(String packageName) { synchronized (mCarrierPrivilegedLock) { if (mCarrierPrivilegedApps == null) { fetchCarrierPrivilegedAppsCPL(); } if (mCarrierPrivilegedApps != null) { return mCarrierPrivilegedApps.contains(packageName); for (int i = mCarrierPrivilegedApps.size() - 1; i >= 0; i--) { if (mCarrierPrivilegedApps.valueAt(i).contains(packageName)) { return true; } } } return false; } } private void clearCarrierPrivilegedApps() { if (DEBUG_BG_RESTRICTION_CONTROLLER) { Slog.i(TAG, "Clearing carrier privileged apps list"); private void registerCarrierPrivilegesCallbacks() { final TelephonyManager telephonyManager = mInjector.getTelephonyManager(); if (telephonyManager == null) { return; } synchronized (mCarrierPrivilegedLock) { mCarrierPrivilegedApps = null; // Need to be refetched. final int numPhones = telephonyManager.getActiveModemCount(); final ArrayList<PhoneCarrierPrivilegesCallback> callbacks = new ArrayList<>(); for (int i = 0; i < numPhones; i++) { final PhoneCarrierPrivilegesCallback callback = new PhoneCarrierPrivilegesCallback(i); callbacks.add(callback); telephonyManager.registerCarrierPrivilegesCallback(i, mBgExecutor, callback); } mCarrierPrivilegesCallbacks = callbacks; } @GuardedBy("mCarrierPrivilegedLock") private void fetchCarrierPrivilegedAppsCPL() { private void unregisterCarrierPrivilegesCallbacks() { final TelephonyManager telephonyManager = mInjector.getTelephonyManager(); mCarrierPrivilegedApps = telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions(); if (DEBUG_BG_RESTRICTION_CONTROLLER) { Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps); if (telephonyManager == null) { return; } final ArrayList<PhoneCarrierPrivilegesCallback> callbacks = mCarrierPrivilegesCallbacks; if (callbacks != null) { for (int i = callbacks.size() - 1; i >= 0; i--) { telephonyManager.unregisterCarrierPrivilegesCallback(callbacks.get(i)); } mCarrierPrivilegesCallbacks = null; } } private class PhoneCarrierPrivilegesCallback implements CarrierPrivilegesCallback { private final int mPhoneId; PhoneCarrierPrivilegesCallback(int phoneId) { mPhoneId = phoneId; } @Override public void onCarrierPrivilegesChanged(@NonNull Set<String> privilegedPackageNames, @NonNull Set<Integer> privilegedUids) { synchronized (mCarrierPrivilegedLock) { mCarrierPrivilegedApps.put(mPhoneId, Collections.unmodifiableSet(privilegedPackageNames)); } } } Loading Loading @@ -3265,7 +3296,6 @@ public final class AppRestrictionController { private void registerForSystemBroadcasts() { final IntentFilter packageFilter = new IntentFilter(); packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); packageFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); packageFilter.addDataScheme("package"); mContext.registerReceiverForAllUsers(mBroadcastReceiver, packageFilter, null, mBgHandler); Loading @@ -3278,6 +3308,9 @@ public final class AppRestrictionController { bootFilter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED); mContext.registerReceiverAsUser(mBootReceiver, UserHandle.SYSTEM, bootFilter, null, mBgHandler); final IntentFilter telFilter = new IntentFilter( TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED); mContext.registerReceiverForAllUsers(mBroadcastReceiver, telFilter, null, mBgHandler); } private void unregisterForSystemBroadcasts() { Loading
services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java +165 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,8 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK; import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE; import static android.os.PowerExemptionManager.REASON_CARRIER_PRIVILEGED_APP; import static android.os.PowerExemptionManager.REASON_DENIED; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; Loading Loading @@ -90,6 +92,7 @@ import static org.mockito.Mockito.anyObject; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; Loading Loading @@ -132,8 +135,10 @@ import android.permission.PermissionManager; import android.provider.DeviceConfig; import android.service.notification.StatusBarNotification; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import androidx.test.runner.AndroidJUnit4; Loading Loading @@ -176,9 +181,12 @@ import java.io.File; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.BiConsumer; Loading Loading @@ -233,8 +241,42 @@ public final class BackgroundRestrictionTest { private static final int BATTERY_FULL_CHARGE_MAH = 5_000; private static final String[] MOCK_PRIVILEGED_PACKAGES_0 = new String[] { TEST_PACKAGE_BASE + 0, TEST_PACKAGE_BASE + 1, }; private static final String[] MOCK_PRIVILEGED_PACKAGES_1 = new String[] { TEST_PACKAGE_BASE + 2, TEST_PACKAGE_BASE + 3, }; private static final String[] MOCK_PRIVILEGED_PACKAGES_2 = new String[] { TEST_PACKAGE_BASE + 4, TEST_PACKAGE_BASE + 5, }; private static final int[] MOCK_PRIVILEGED_UIDS_0 = new int[] { UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 0), UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 1), }; private static final int[] MOCK_PRIVILEGED_UIDS_1 = new int[] { UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 2), UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 3), }; private static final int[] MOCK_PRIVILEGED_UIDS_2 = new int[] { UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 4), UserHandle.getUid(TEST_USER0, TEST_PACKAGE_APPID_BASE + 5), }; private static final String[][] MOCK_PRIVILEGED_PACKAGES = new String[][] { MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_PACKAGES_1, }; private static final int[][] MOCK_PRIVILEGED_UIDS = new int[][] { MOCK_PRIVILEGED_UIDS_0, MOCK_PRIVILEGED_UIDS_1, }; @Mock private ActivityManagerInternal mActivityManagerInternal; @Mock private ActivityManagerService mActivityManagerService; @Mock private ActivityManagerConstants mActivityManagerConstants; @Mock private AppOpsManager mAppOpsManager; @Mock private AppStandbyInternal mAppStandbyInternal; @Mock private AppHibernationManagerInternal mAppHibernationInternal; Loading @@ -255,6 +297,8 @@ public final class BackgroundRestrictionTest { @Mock private TelephonyManager mTelephonyManager; @Mock private IAppOpsService mIAppOpsService; private PhoneCarrierPrivileges mPhoneCarrierPrivileges; private long mCurrentTimeMillis; @Captor private ArgumentCaptor<AppStateTracker.BackgroundRestrictedAppListener> mFasListenerCap; Loading Loading @@ -298,6 +342,14 @@ public final class BackgroundRestrictionTest { mBgRestrictionController = spy(new AppRestrictionController(mInjector, mActivityManagerService)); mActivityManagerService.mConstants = mActivityManagerConstants; mPhoneCarrierPrivileges = new PhoneCarrierPrivileges( mInjector.getTelephonyManager(), MOCK_PRIVILEGED_PACKAGES.length); for (int i = 0; i < MOCK_PRIVILEGED_PACKAGES.length; i++) { mPhoneCarrierPrivileges.addNewPrivilegePackages(i, MOCK_PRIVILEGED_PACKAGES[i], MOCK_PRIVILEGED_UIDS[i]); } doReturn(PROCESS_STATE_FOREGROUND_SERVICE).when(mActivityManagerInternal) .getUidProcessState(anyInt()); doReturn(TEST_USERS).when(mUserManagerInternal).getUserIds(); Loading Loading @@ -2984,6 +3036,78 @@ public final class BackgroundRestrictionTest { verifyLoadedSettings(settings); } @Test public void testCarrierPrivilegedAppListener() throws Exception { final long shortMs = 1_000L; for (int i = 0; i < MOCK_PRIVILEGED_PACKAGES.length; i++) { verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES[i], MOCK_PRIVILEGED_UIDS[i]); } verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); mPhoneCarrierPrivileges.addNewPrivilegePackages(0, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); Thread.sleep(shortMs); verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_UIDS_0); verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES_1, MOCK_PRIVILEGED_UIDS_1); mPhoneCarrierPrivileges.addNewPrivilegePackages(1, new String[0], new int[0]); Thread.sleep(shortMs); verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_UIDS_0); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_1, MOCK_PRIVILEGED_UIDS_1); mPhoneCarrierPrivileges.addNewPrivilegePackages(0, MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_UIDS_0); Thread.sleep(shortMs); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_2, MOCK_PRIVILEGED_UIDS_2); verifyPotentialSystemExemptionReason(REASON_CARRIER_PRIVILEGED_APP, MOCK_PRIVILEGED_PACKAGES_0, MOCK_PRIVILEGED_UIDS_0); verifyPotentialSystemExemptionReason(REASON_DENIED, MOCK_PRIVILEGED_PACKAGES_1, MOCK_PRIVILEGED_UIDS_1); } private void verifyPotentialSystemExemptionReason(int expectedReason, String[] packages, int[] uids) throws Exception { for (int i = 0; i < packages.length; i++) { assertEquals(expectedReason, mBgRestrictionController.getPotentialSystemExemptionReason( uids[i], packages[i])); } } private void verifyLoadedSettings(RestrictionSettings settings) throws Exception { // Make a new copy and reset it. RestrictionSettings test = (RestrictionSettings) settings.clone(); Loading Loading @@ -3019,6 +3143,47 @@ public final class BackgroundRestrictionTest { return result; } private class PhoneCarrierPrivileges { private final SparseArray<Pair<String[], int[]>> mPackages = new SparseArray<>(); private final SparseArray<Pair<Executor, CarrierPrivilegesCallback>> mListeners = new SparseArray<>(); PhoneCarrierPrivileges(TelephonyManager telephonyManager, int phoneIds) { doReturn(phoneIds).when(telephonyManager).getActiveModemCount(); doAnswer(inv -> { registerCarrierPrivilegesCallback( inv.getArgument(0), inv.getArgument(1), inv.getArgument(2)); return null; }).when(telephonyManager).registerCarrierPrivilegesCallback( anyInt(), anyObject(), anyObject()); } public void registerCarrierPrivilegesCallback(int phoneId, Executor executor, CarrierPrivilegesCallback callback) { mListeners.put(phoneId, Pair.create(executor, callback)); final Pair<String[], int[]> pkgs = mPackages.get(phoneId); final Set<String> pkgNames = pkgs != null ? Arrays.stream(pkgs.first).collect(Collectors.toUnmodifiableSet()) : Collections.emptySet(); final Set<Integer> uids = pkgs != null ? Arrays.stream(pkgs.second).boxed().collect(Collectors.toUnmodifiableSet()) : Collections.emptySet(); executor.execute(() -> callback.onCarrierPrivilegesChanged(pkgNames, uids)); } public void addNewPrivilegePackages(int phoneId, String[] pkgNames, int[] uids) { mPackages.put(phoneId, Pair.create(pkgNames, uids)); final Pair<Executor, CarrierPrivilegesCallback> callback = mListeners.get(phoneId); if (callback != null) { callback.first.execute(() -> callback.second.onCarrierPrivilegesChanged( Arrays.stream(pkgNames).collect(Collectors.toUnmodifiableSet()), Arrays.stream(uids).boxed().collect(Collectors.toUnmodifiableSet()))); } } } private class TestBgRestrictionInjector extends AppRestrictionController.Injector { private Context mContext; Loading