Merge "Add listener on carrier privileged app changes for exempted FGS type" into udc-dev
This commit is contained in:
@@ -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;
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
@@ -413,6 +409,10 @@ public final class AppRestrictionController {
|
||||
onUserRemoved(userId);
|
||||
}
|
||||
} break;
|
||||
case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED: {
|
||||
unregisterCarrierPrivilegesCallbacks();
|
||||
registerCarrierPrivilegesCallbacks();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1501,6 +1501,7 @@ public final class AppRestrictionController {
|
||||
initRolesInInterest();
|
||||
registerForUidObservers();
|
||||
registerForSystemBroadcasts();
|
||||
registerCarrierPrivilegesCallbacks();
|
||||
mNotificationHelper.onSystemReady();
|
||||
mInjector.getAppStateTracker().addBackgroundRestrictedAppListener(
|
||||
mBackgroundRestrictionListener);
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
private void unregisterCarrierPrivilegesCallbacks() {
|
||||
final TelephonyManager telephonyManager = mInjector.getTelephonyManager();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mCarrierPrivilegedLock")
|
||||
private void fetchCarrierPrivilegedAppsCPL() {
|
||||
final TelephonyManager telephonyManager = mInjector.getTelephonyManager();
|
||||
mCarrierPrivilegedApps =
|
||||
telephonyManager.getCarrierPrivilegedPackagesForAllActiveSubscriptions();
|
||||
if (DEBUG_BG_RESTRICTION_CONTROLLER) {
|
||||
Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user