Merge "Add listener on carrier privileged app changes for exempted FGS type" into udc-dev

This commit is contained in:
Jing Ji
2023-04-04 01:08:26 +00:00
committed by Android (Google) Code Review
2 changed files with 231 additions and 33 deletions

View File

@@ -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() {

View File

@@ -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;