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

Commit a7c60c04 authored by Hai Zhang's avatar Hai Zhang
Browse files

Reset mode for app op permission when app no longer requests it.

Fixes: 149765004
Test: Ensure the same set of tests pass with the following command:
Test: atest ExternalStorageHostTest StorageHostTest
Change-Id: Ic3847f136e059e3517154b909d07b68553ebf82b
parent bba1891e
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -4607,11 +4607,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        }

        @Override
        public @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtection(
        public @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtection(
                @PermissionInfo.Protection int protection) {
            ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();

            synchronized (PermissionManagerService.this.mLock) {
            synchronized (mLock) {
                int numTotalPermissions = mSettings.mPermissions.size();

                for (int i = 0; i < numTotalPermissions; i++) {
@@ -4627,6 +4627,28 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            return matchingPermissions;
        }

        @Override
        public @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
                @PermissionInfo.ProtectionFlags int protectionFlags) {
            ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();

            synchronized (mLock) {
                int numTotalPermissions = mSettings.mPermissions.size();

                for (int i = 0; i < numTotalPermissions; i++) {
                    BasePermission bp = mSettings.mPermissions.valueAt(i);

                    if (bp.perm != null && (bp.perm.getProtectionFlags() & protectionFlags)
                            == protectionFlags) {
                        matchingPermissions.add(
                                PackageInfoUtils.generatePermissionInfo(bp.perm, 0));
                    }
                }
            }

            return matchingPermissions;
        }

        @Override
        public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
            return PermissionManagerService.this.backupRuntimePermissions(user);
+6 −2
Original line number Diff line number Diff line
@@ -302,10 +302,14 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
    /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
    public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);

    /** Get all permission that have a certain protection level */
    public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtection(
    /** Get all permissions that have a certain protection */
    public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtection(
            @PermissionInfo.Protection int protection);

    /** Get all permissions that have certain protection flags */
    public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
            @PermissionInfo.ProtectionFlags int protectionFlags);

    /**
     * Returns the delegate used to influence permission checking.
     *
+108 −8
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -107,6 +108,15 @@ public final class PermissionPolicyService extends SystemService {
    @GuardedBy("mLock")
    private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>();

    /**
     * Whether an async {@link #resetAppOpPermissionsIfNotRequestedForUid} is currently
     * scheduled for a uid.
     */
    @GuardedBy("mLock")
    private final SparseBooleanArray mIsUidSyncScheduled = new SparseBooleanArray();

    private List<String> mAppOpPermissions;

    public PermissionPolicyService(@NonNull Context context) {
        super(context);

@@ -117,7 +127,7 @@ public final class PermissionPolicyService extends SystemService {
    public void onStart() {
        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
                PackageManagerInternal.class);
        final PermissionManagerServiceInternal permManagerInternal = LocalServices.getService(
        final PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
                PermissionManagerServiceInternal.class);
        final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
                ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -125,38 +135,44 @@ public final class PermissionPolicyService extends SystemService {
        packageManagerInternal.getPackageList(new PackageListObserver() {
            @Override
            public void onPackageAdded(String packageName, int uid) {
                onPackageChanged(packageName, uid);
                final int userId = UserHandle.getUserId(uid);
                if (isStarted(userId)) {
                    synchronizePackagePermissionsAndAppOpsForUser(packageName, userId);
                }
            }

            @Override
            public void onPackageChanged(String packageName, int uid) {
                final int userId = UserHandle.getUserId(uid);

                if (isStarted(userId)) {
                    synchronizePackagePermissionsAndAppOpsForUser(packageName, userId);
                    resetAppOpPermissionsIfNotRequestedForUid(uid);
                }
            }

            @Override
            public void onPackageRemoved(String packageName, int uid) {
                /* do nothing */
                final int userId = UserHandle.getUserId(uid);
                if (isStarted(userId)) {
                    resetAppOpPermissionsIfNotRequestedForUid(uid);
                }
            }
        });

        permManagerInternal.addOnRuntimePermissionStateChangedListener(
        permissionManagerInternal.addOnRuntimePermissionStateChangedListener(
                this::synchronizePackagePermissionsAndAppOpsAsyncForUser);

        mAppOpsCallback = new IAppOpsCallback.Stub() {
            public void opChanged(int op, int uid, String packageName) {
                synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
                        UserHandle.getUserId(uid));
                resetAppOpPermissionsIfNotRequestedForUidAsync(uid);
            }
        };

        final ArrayList<PermissionInfo> dangerousPerms =
                permManagerInternal.getAllPermissionWithProtection(
                permissionManagerInternal.getAllPermissionsWithProtection(
                        PermissionInfo.PROTECTION_DANGEROUS);

        try {
            int numDangerousPerms = dangerousPerms.size();
            for (int i = 0; i < numDangerousPerms; i++) {
@@ -179,6 +195,26 @@ public final class PermissionPolicyService extends SystemService {
            Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
        }

        final List<PermissionInfo> appOpPermissionInfos =
                permissionManagerInternal.getAllPermissionsWithProtectionFlags(
                        PermissionInfo.PROTECTION_FLAG_APPOP);
        mAppOpPermissions = new ArrayList<>();
        final int appOpPermissionInfosSize = appOpPermissionInfos.size();
        for (int i = 0; i < appOpPermissionInfosSize; i++) {
            final PermissionInfo appOpPermissionInfo = appOpPermissionInfos.get(i);

            final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermissionInfo.name);
            if (appOpCode != OP_NONE) {
                mAppOpPermissions.add(appOpPermissionInfo.name);

                try {
                    appOpsService.startWatchingMode(appOpCode, null, mAppOpsCallback);
                } catch (RemoteException e) {
                    Slog.wtf(LOG_TAG, "Cannot set up app-ops listener", e);
                }
            }
        }

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -445,6 +481,70 @@ public final class PermissionPolicyService extends SystemService {
        synchronizer.syncPackages();
    }

    private void resetAppOpPermissionsIfNotRequestedForUidAsync(int uid) {
        if (isStarted(UserHandle.getUserId(uid))) {
            synchronized (mLock) {
                if (!mIsUidSyncScheduled.get(uid)) {
                    mIsUidSyncScheduled.put(uid, true);
                    FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
                            PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid,
                            this, uid));
                }
            }
        }
    }

    private void resetAppOpPermissionsIfNotRequestedForUid(int uid) {
        synchronized (mLock) {
            mIsUidSyncScheduled.delete(uid);
        }

        final Context context = getContext();
        final PackageManager userPackageManager = getUserContext(context,
                UserHandle.getUserHandleForUid(uid)).getPackageManager();
        final String[] packageNames = userPackageManager.getPackagesForUid(uid);
        if (packageNames == null || packageNames.length == 0) {
            return;
        }

        final ArraySet<String> requestedPermissions = new ArraySet<>();
        for (String packageName : packageNames) {
            final PackageInfo packageInfo;
            try {
                packageInfo = userPackageManager.getPackageInfo(packageName, GET_PERMISSIONS);
            } catch (NameNotFoundException e) {
                continue;
            }
            if (packageInfo == null || packageInfo.requestedPermissions == null) {
                continue;
            }
            Collections.addAll(requestedPermissions, packageInfo.requestedPermissions);
        }

        final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
        final AppOpsManagerInternal appOpsManagerInternal = LocalServices.getService(
                AppOpsManagerInternal.class);
        final int appOpPermissionsSize = mAppOpPermissions.size();
        for (int i = 0; i < appOpPermissionsSize; i++) {
            final String appOpPermission = mAppOpPermissions.get(i);

            if (!requestedPermissions.contains(appOpPermission)) {
                final int appOpCode = AppOpsManager.permissionToOpCode(appOpPermission);
                final int defaultAppOpMode = AppOpsManager.opToDefaultMode(appOpCode);
                for (String packageName : packageNames) {
                    final int appOpMode = appOpsManager.unsafeCheckOpRawNoThrow(appOpCode, uid,
                            packageName);
                    if (appOpMode != defaultAppOpMode) {
                        appOpsManagerInternal.setUidModeFromPermissionPolicy(appOpCode, uid,
                                defaultAppOpMode, mAppOpsCallback);
                        appOpsManagerInternal.setModeFromPermissionPolicy(appOpCode, uid,
                                packageName, defaultAppOpMode, mAppOpsCallback);
                    }
                }
            }
        }
    }

    /**
     * Synchronizes permission to app ops. You *must* always sync all packages
     * in a shared UID at the same time to ensure proper synchronization.
@@ -499,7 +599,7 @@ public final class PermissionPolicyService extends SystemService {
            PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
                    PermissionManagerServiceInternal.class);
            List<PermissionInfo> permissionInfos =
                    permissionManagerInternal.getAllPermissionWithProtection(
                    permissionManagerInternal.getAllPermissionsWithProtection(
                            PermissionInfo.PROTECTION_DANGEROUS);
            int permissionInfosSize = permissionInfos.size();
            for (int i = 0; i < permissionInfosSize; i++) {