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

Commit 0684160d authored by Evan Severson's avatar Evan Severson
Browse files

Fix users' permissions with bg mic/camera

When the background mic/camera changes were submitted the system started
exempting preinstalled apps to use the permissions. The state can be
corrected since the erroneous exemptions have been fixed.

This can take a couple seconds so it's been decided to fix the state
after boot, this may cause an app to be killed while using it but this
would be very rare and there's only one chance for it to happen.

This change should be reverted after an update is pushed. Fairly
verbose logging (which should only happen at once on boot) is being
added so any issues this causes can be easily debugged to avoid leaving
users in a bad state.

Bug: 169856898
Bug: 158311343
Test: Push build without this change, delete permissions db, boot,
          assert bad permission state, push this change, boot
Change-Id: I7f2729b3f5ce19759548969f54632f8b08be8261
parent e372d996
Loading
Loading
Loading
Loading
+106 −0
Original line number Diff line number Diff line
@@ -70,11 +70,16 @@ import android.app.ApplicationPackageManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.role.RoleManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PermissionGroupInfoFlags;
import android.content.pm.PackageManager.PermissionInfoFlags;
@@ -84,6 +89,7 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -177,6 +183,7 @@ import java.util.function.Consumer;
 */
public class PermissionManagerService extends IPermissionManager.Stub {
    private static final String TAG = "PackageManager";
    private static final String LOG_TAG = PermissionManagerService.class.getSimpleName();

    private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60);

@@ -420,6 +427,105 @@ public class PermissionManagerService extends IPermissionManager.Stub {
                new PermissionManagerServiceInternalImpl();
        LocalServices.addService(PermissionManagerServiceInternal.class, localService);
        LocalServices.addService(PermissionManagerInternal.class, localService);

        context.getMainThreadHandler().post(() -> context.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
                    return;
                }

                try {
                    fixBgMicCamera(context);
                } catch (Throwable t) {
                    // Don't crash the system if this fails for any reason. Any intermediate state
                    // this can leave the permissions in is okay and in the worst case the state is
                    // the same as before the user rebooted.
                    Log.e(LOG_TAG, "Unable to fix background permissions", t);
                }
            }


            private void fixBgMicCamera(Context context) {
                PackageManager pm = context.getPackageManager();
                for (UserInfo userInfo : context.getSystemService(UserManager.class).getUsers()) {
                    UserHandle user = userInfo.getUserHandle();
                    List<String> assistants = context.getSystemService(RoleManager.class)
                            .getRoleHoldersAsUser(RoleManager.ROLE_ASSISTANT, user);
                    List<PackageInfo> packages =
                            pm.getInstalledPackagesAsUser(PackageManager.MATCH_SYSTEM_ONLY
                                    | PackageManager.GET_PERMISSIONS, user.getIdentifier());
                    for (PackageInfo packageInfo : packages) {
                        String[] requestedPermissions = packageInfo.requestedPermissions;
                        if (requestedPermissions == null) {
                            continue;
                        }
                        for (String permName : requestedPermissions) {
                            String pkg = packageInfo.packageName;
                            switch (permName) {
                                case Manifest.permission.BACKGROUND_CAMERA:
                                    removeFromAllowlistsAndRevoke(pm, pkg, permName, user);
                                    break;
                                case Manifest.permission.RECORD_BACKGROUND_AUDIO:
                                    if (assistants.contains(pkg)) {
                                        removeFromAllowlistsAndRevokeForAssistant(pm, pkg, permName,
                                                user);
                                    } else {
                                        removeFromAllowlistsAndRevoke(pm, pkg, permName, user);
                                    }
                                    break;
                            }
                        }
                    }
                }
            }

            private void removeFromAllowlistsAndRevoke(PackageManager pm, String pkg,
                    String permName, UserHandle user) {
                if ((pm.getPermissionFlags(permName, pkg, user)
                        & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0) {
                    Slog.i(LOG_TAG, "removing " + pkg + " " + permName + " from all allowlists");
                    pm.removeWhitelistedRestrictedPermission(pkg, permName,
                            FLAG_PERMISSION_WHITELIST_UPGRADE);
                    pm.removeWhitelistedRestrictedPermission(pkg, permName,
                            FLAG_PERMISSION_WHITELIST_SYSTEM);
                    pm.removeWhitelistedRestrictedPermission(pkg, permName,
                            FLAG_PERMISSION_WHITELIST_INSTALLER);
                    pm.removeWhitelistedRestrictedPermission(pkg, permName,
                            FLAG_PERMISSION_ALLOWLIST_ROLE);
                }
                if (pm.checkPermission(permName, pkg) == PackageManager.PERMISSION_GRANTED) {
                    Slog.i(LOG_TAG, "revoking " + pkg + " " + permName);
                    pm.revokeRuntimePermission(pkg, permName, user);
                }
            }

            private void removeFromAllowlistsAndRevokeForAssistant(PackageManager pm, String pkg,
                    String permName, UserHandle user) {
                int anyNonRoleExempt =
                        FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
                                | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
                                | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;

                if ((pm.getPermissionFlags(permName, pkg, user) & anyNonRoleExempt) != 0) {
                    Slog.i(LOG_TAG, "removing " + pkg + " " + permName
                            + " from all allowlists except role");
                    pm.removeWhitelistedRestrictedPermission(pkg, permName,
                            FLAG_PERMISSION_WHITELIST_UPGRADE);
                    pm.removeWhitelistedRestrictedPermission(pkg, permName,
                            FLAG_PERMISSION_WHITELIST_SYSTEM);
                    pm.removeWhitelistedRestrictedPermission(pkg, permName,
                            FLAG_PERMISSION_WHITELIST_INSTALLER);
                }
                if ((pm.getPermissionFlags(permName, pkg, user)
                        & FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT) == 0) {
                    Slog.i(LOG_TAG, "adding " + pkg + " " + permName
                            + " to role allowlist");
                    pm.addWhitelistedRestrictedPermission(pkg, permName,
                            FLAG_PERMISSION_ALLOWLIST_ROLE);
                }
            }
        }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)));
    }

    @Override