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

Commit 610f58e7 authored by Philip P. Moltmann's avatar Philip P. Moltmann Committed by android-build-merger
Browse files

Make perm policy sve ready for additional usages

am: bd4943b4

Change-Id: Id5979689be6bc8cf9426ead689cbc6d4910c3c7f
parents 03523ea6 bd4943b4
Loading
Loading
Loading
Loading
+137 −64
Original line number Diff line number Diff line
@@ -158,6 +158,9 @@ public final class PermissionPolicyService extends SystemService {
                });
    }

    /**
     * Synchronize a single package.
     */
    private static void synchronizePackagePermissionsAndAppOpsForUser(@NonNull Context context,
            @NonNull String packageName, @UserIdInt int userId) {
        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
@@ -167,7 +170,7 @@ public final class PermissionPolicyService extends SystemService {
            return;
        }
        final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(context);
        synchroniser.addPackage(context, pkg, userId);
        synchroniser.addPackage(pkg, userId);
        final String[] sharedPkgNames = packageManagerInternal.getPackagesForSharedUserId(
                pkg.mSharedUserId, userId);
        if (sharedPkgNames != null) {
@@ -175,20 +178,23 @@ public final class PermissionPolicyService extends SystemService {
                final PackageParser.Package sharedPkg = packageManagerInternal
                        .getPackage(sharedPkgName);
                if (sharedPkg != null) {
                    synchroniser.addPackage(context, sharedPkg, userId);
                    synchroniser.addPackage(sharedPkg, userId);
                }
            }
        }
        synchroniser.syncPackages();
    }

    /**
     * Synchronize all packages
     */
    private static void synchronizePermissionsAndAppOpsForUser(@NonNull Context context,
            @UserIdInt int userId) {
        final PackageManagerInternal packageManagerInternal = LocalServices.getService(
                PackageManagerInternal.class);
        final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(context);
        packageManagerInternal.forEachPackage((pkg) ->
                synchronizer.addPackage(context, pkg, userId));
                synchronizer.addPackage(pkg, userId));
        synchronizer.syncPackages();
    }

@@ -198,17 +204,39 @@ public final class PermissionPolicyService extends SystemService {
     */
    private static class PermissionToOpSynchroniser {
        private final @NonNull Context mContext;
        private final @NonNull PackageManager mPackageManager;
        private final @NonNull AppOpsManager mAppOpsManager;

        /** All uid that need to be synchronized */
        private final @NonNull SparseIntArray mAllUids = new SparseIntArray();

        private final @NonNull SparseIntArray mUids = new SparseIntArray();
        private final @NonNull SparseArray<String> mPackageNames = new SparseArray<>();
        private final @NonNull SparseIntArray mAllowedUidOps = new SparseIntArray();
        private final @NonNull SparseIntArray mDefaultUidOps = new SparseIntArray();
        /**
         * All ops that need to be restricted
         *
         * @see #syncRestrictedOps
         */
        private final @NonNull ArrayList<OpToRestrict> mOpsToRestrict = new ArrayList<>();
        /**
         * All ops that need to be unrestricted
         *
         * @see #syncRestrictedOps
         */
        private final @NonNull ArrayList<OpToUnrestrict> mOpsToUnrestrict = new ArrayList<>();

        PermissionToOpSynchroniser(@NonNull Context context) {
            mContext = context;
            mPackageManager = context.getPackageManager();
            mAppOpsManager = context.getSystemService(AppOpsManager.class);
        }

        void syncPackages() {
        /**
         * Set app ops that belong to restricted permissions.
         *
         * <p>This processes ops previously added by {@link #addOpIfRestricted}
         */
        private void syncRestrictedOps() {
            final SparseIntArray unprocessedUids = mAllUids.clone();

            // TRICKY: we set the app op for a restricted permission to allow if the app
            // requesting the permission is whitelisted and to deny if the app requesting
            // the permission is not whitelisted. However, there is another case where an
@@ -222,52 +250,48 @@ public final class PermissionPolicyService extends SystemService {
            final SparseArray<List<String>> unrequestedRestrictedPermissionsForUid =
                    new SparseArray<>();

            final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
            final int allowedCount = mAllowedUidOps.size();
            for (int i = 0; i < allowedCount; i++) {
                final int opCode = mAllowedUidOps.keyAt(i);
                final int uid = mAllowedUidOps.valueAt(i);
                final String packageName = mPackageNames.valueAt(i);
                setUidModeAllowed(appOpsManager, opCode, uid, packageName);
            final int unrestrictCount = mOpsToUnrestrict.size();
            for (int i = 0; i < unrestrictCount; i++) {
                final OpToUnrestrict op = mOpsToUnrestrict.get(i);
                setUidModeAllowed(op.code, op.uid, op.packageName);

                // Keep track this permission was requested by the UID.
                List<String> unrequestedRestrictedPermissions =
                        unrequestedRestrictedPermissionsForUid.get(uid);
                        unrequestedRestrictedPermissionsForUid.get(op.uid);
                if (unrequestedRestrictedPermissions == null) {
                    unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions);
                    unrequestedRestrictedPermissionsForUid.put(uid,
                    unrequestedRestrictedPermissionsForUid.put(op.uid,
                            unrequestedRestrictedPermissions);
                }
                unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode));
                unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code));

                mUids.delete(uid);
                unprocessedUids.delete(op.uid);
            }
            final int defaultCount = mDefaultUidOps.size();
            for (int i = 0; i < defaultCount; i++) {
                final int opCode = mDefaultUidOps.keyAt(i);
                final int uid = mDefaultUidOps.valueAt(i);
                setUidModeDefault(appOpsManager, opCode, uid);
            final int restrictCount = mOpsToRestrict.size();
            for (int i = 0; i < restrictCount; i++) {
                final OpToRestrict op = mOpsToRestrict.get(i);
                setUidModeDefault(op.code, op.uid);

                // Keep track this permission was requested by the UID.
                List<String> unrequestedRestrictedPermissions =
                        unrequestedRestrictedPermissionsForUid.get(uid);
                        unrequestedRestrictedPermissionsForUid.get(op.uid);
                if (unrequestedRestrictedPermissions == null) {
                    unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions);
                    unrequestedRestrictedPermissionsForUid.put(uid,
                    unrequestedRestrictedPermissionsForUid.put(op.uid,
                            unrequestedRestrictedPermissions);
                }
                unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode));
                unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code));

                mUids.delete(uid);
                unprocessedUids.delete(op.uid);
            }

            // Give root access
            mUids.put(Process.ROOT_UID, Process.ROOT_UID);
            unprocessedUids.put(Process.ROOT_UID, Process.ROOT_UID);

            // Add records for UIDs that don't use any restricted permissions.
            final int uidCount = mUids.size();
            final int uidCount = unprocessedUids.size();
            for (int i = 0; i < uidCount; i++) {
                final int uid = mUids.keyAt(i);
                final int uid = unprocessedUids.keyAt(i);
                unrequestedRestrictedPermissionsForUid.put(uid,
                        new ArrayList<>(sAllRestrictedPermissions));
            }
@@ -289,8 +313,7 @@ public final class PermissionPolicyService extends SystemService {
                    for (int j = 0; j < permissionCount; j++) {
                        final String permission = unrequestedRestrictedPermissions.get(j);
                        for (String packageName : packageNames) {
                            setUidModeAllowed(appOpsManager,
                                    AppOpsManager.permissionToOpCode(permission), uid,
                            setUidModeAllowed(AppOpsManager.permissionToOpCode(permission), uid,
                                    packageName);
                        }
                    }
@@ -298,14 +321,61 @@ public final class PermissionPolicyService extends SystemService {
            }
        }

        private void addPackage(@NonNull Context context,
                @NonNull PackageParser.Package pkg, @UserIdInt int userId) {
            final PackageManager packageManager = context.getPackageManager();
        /**
         * Synchronize all previously {@link #addPackage added} packages.
         */
        void syncPackages() {
            syncRestrictedOps();
        }

        /**
         * Add op that belong to a restricted permission for later processing in
         * {@link #syncRestrictedOps}.
         *
         * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
         *
         * @param permissionInfo The permission that is currently looked at
         * @param pkg The package looked at
         * @param userId The user the package belongs to
         */
        private void addOpIfRestricted(@NonNull PermissionInfo permissionInfo,
                @NonNull PackageParser.Package pkg, @UserIdInt int userId) {
            final String permission = permissionInfo.name;
            final int opCode = AppOpsManager.permissionToOpCode(permission);
            final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid));
            final UserHandle userHandle = UserHandle.of(userId);

            mUids.put(uid, uid);
            if (!permissionInfo.isRestricted()) {
                return;
            }

            final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED
                    && (mPackageManager.getPermissionFlags(permission, pkg.packageName,
                    userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;

            if (permissionInfo.isHardRestricted()) {
                if (applyRestriction) {
                    mOpsToRestrict.add(new OpToRestrict(uid, opCode));
                } else {
                    mOpsToUnrestrict.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
                }
            } else if (permissionInfo.isSoftRestricted()) {
                //TODO: Implement soft restrictions like storage here.
            }
        }

        /**
         * Add a package for {@link #syncPackages() processing} later.
         *
         * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
         *
         * @param pkg The package to add for later processing
         * @param userId The user the package belongs to
         */
        void addPackage(@NonNull PackageParser.Package pkg, @UserIdInt int userId) {
            final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid));

            mAllUids.put(uid, uid);

            final int permissionCount = pkg.requestedPermissions.size();
            for (int i = 0; i < permissionCount; i++) {
@@ -318,44 +388,47 @@ public final class PermissionPolicyService extends SystemService {

                final PermissionInfo permissionInfo;
                try {
                    permissionInfo = packageManager.getPermissionInfo(permission, 0);
                    permissionInfo = mPackageManager.getPermissionInfo(permission, 0);
                } catch (PackageManager.NameNotFoundException e) {
                    continue;
                }

                if (!permissionInfo.isRestricted()) {
                    continue;
                addOpIfRestricted(permissionInfo, pkg, userId);
            }

                final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED
                        && (packageManager.getPermissionFlags(permission, pkg.packageName,
                                userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;

                if (permissionInfo.isHardRestricted()) {
                    if (applyRestriction) {
                        mDefaultUidOps.put(opCode, uid);
                    } else {
                        mPackageNames.put(opCode, pkg.packageName);
                        mAllowedUidOps.put(opCode, uid);
        }
                } else if (permissionInfo.isSoftRestricted()) {
                    //TODO: Implement soft restrictions like storage here.

        private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
            final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
                    .opToPublicName(opCode), uid, packageName);
            if (currentMode == AppOpsManager.MODE_DEFAULT) {
                mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
            }
        }

        private void setUidModeDefault(int opCode, int uid) {
            mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT);
        }

        private static void setUidModeAllowed(@NonNull AppOpsManager appOpsManager,
                int opCode, int uid, @NonNull String packageName) {
            final int currentMode = appOpsManager.unsafeCheckOpRaw(AppOpsManager
                    .opToPublicName(opCode), uid, packageName);
            if (currentMode == AppOpsManager.MODE_DEFAULT) {
                appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
        private class OpToRestrict {
            final int uid;
            final int code;

            OpToRestrict(int uid, int code) {
                this.uid = uid;
                this.code = code;
            }
        }

        private static void setUidModeDefault(@NonNull AppOpsManager appOpsManager,
                int opCode, int uid) {
            appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT);
        private class OpToUnrestrict {
            final int uid;
            final @NonNull String packageName;
            final int code;

            OpToUnrestrict(int uid, @NonNull String packageName, int code) {
                this.uid = uid;
                this.packageName = packageName;
                this.code = code;
            }
        }
    }
}