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

Commit ece028ad authored by Jing Ji's avatar Jing Ji Committed by Android (Google) Code Review
Browse files

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

parents 8f23f6bb e39d8cc8
Loading
Loading
Loading
Loading
+65 −32
Original line number Diff line number Diff line
@@ -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;
    }

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

@@ -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() {
+165 −0
Original line number Diff line number Diff line
@@ -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;