summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/AppRestrictionController.java97
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java165
2 files changed, 230 insertions, 32 deletions
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 6928bd307af0..81a2fc5277a0 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -136,6 +136,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;
@@ -311,10 +312,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.
@@ -357,19 +366,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);
@@ -412,6 +408,10 @@ public final class AppRestrictionController {
onUserRemoved(userId);
}
} break;
+ case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED: {
+ unregisterCarrierPrivilegesCallbacks();
+ registerCarrierPrivilegesCallbacks();
+ } break;
}
}
};
@@ -1508,6 +1508,7 @@ public final class AppRestrictionController {
initRolesInInterest();
registerForUidObservers();
registerForSystemBroadcasts();
+ registerCarrierPrivilegesCallbacks();
mNotificationHelper.onSystemReady();
mInjector.getAppStateTracker().addBackgroundRestrictedAppListener(
mBackgroundRestrictionListener);
@@ -2823,6 +2824,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;
@@ -2836,7 +2838,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) {
@@ -2879,32 +2881,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));
+ }
}
}
@@ -3272,7 +3303,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);
@@ -3285,6 +3315,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() {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index 3042edec6aad..bad04dc020c7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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();
@@ -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();
@@ -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;