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

Commit 48f36c6a authored by Hai Zhang's avatar Hai Zhang
Browse files

Cache service component name in RoleControllerManager to avoid deadlock.

PackageManagerService needs to know the default home/browser app,
often with the PackageManagerService lock held, so we should avoid
holding the RoleManagerService lock and trying to acquire the
PackageManagerService lock.

Right now the only place we need to access PackageManager while
holding RoleManagerService lock is when creating a
RoleControllerManager, but actually the component name of the remote
service should be the same for any user, so we can just cache the
component name upfront to avoid the deadlock.

Bug: 130130942
Bug: 130303431
Test: manual
Change-Id: Id19edb362a1524663d8d3eb27cef161cf1fa4542
parent 21df0436
Loading
Loading
Loading
Loading
+38 −8
Original line number Diff line number Diff line
@@ -52,7 +52,10 @@ public class RoleControllerManager {

    private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();

    private static volatile ComponentName sRemoteServiceComponentName;

    private static final Object sRemoteServicesLock = new Object();

    /**
     * Global remote services (per user) used by all {@link RoleControllerManager managers}.
     */
@@ -62,18 +65,36 @@ public class RoleControllerManager {
    @NonNull
    private final RemoteService mRemoteService;

    public RoleControllerManager(@NonNull Context context, @NonNull Handler handler) {
    /**
     * Initialize the remote service component name once so that we can avoid acquiring the
     * PackageManagerService lock in constructor.
     *
     * @see #createWithInitializedRemoteServiceComponentName(Handler, Context)
     */
    public static void initializeRemoteServiceComponentName(@NonNull Context context) {
        sRemoteServiceComponentName = getRemoteServiceComponentName(context);
    }

    /**
     * Create a {@link RoleControllerManager} instance with the initialized remote service component
     * name so that we can avoid acquiring the PackageManagerService lock in constructor.
     *
     * @see #initializeRemoteServiceComponentName(Context)
     */
    @NonNull
    public static RoleControllerManager createWithInitializedRemoteServiceComponentName(
            @NonNull Handler handler, @NonNull Context context) {
        return new RoleControllerManager(sRemoteServiceComponentName, handler, context);
    }

    private RoleControllerManager(@NonNull ComponentName remoteServiceComponentName,
            @NonNull Handler handler, @NonNull Context context) {
        synchronized (sRemoteServicesLock) {
            int userId = context.getUserId();
            RemoteService remoteService = sRemoteServices.get(userId);
            if (remoteService == null) {
                Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
                PackageManager packageManager = context.getPackageManager();
                intent.setPackage(packageManager.getPermissionControllerPackageName());
                ResolveInfo resolveInfo = packageManager.resolveService(intent, 0);

                remoteService = new RemoteService(context.getApplicationContext(),
                        resolveInfo.getComponentInfo().getComponentName(), handler, userId);
                        remoteServiceComponentName, handler, userId);
                sRemoteServices.put(userId, remoteService);
            }
            mRemoteService = remoteService;
@@ -81,7 +102,16 @@ public class RoleControllerManager {
    }

    public RoleControllerManager(@NonNull Context context) {
        this(context, context.getMainThreadHandler());
        this(getRemoteServiceComponentName(context), context.getMainThreadHandler(), context);
    }

    @NonNull
    private static ComponentName getRemoteServiceComponentName(@NonNull Context context) {
        Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
        PackageManager packageManager = context.getPackageManager();
        intent.setPackage(packageManager.getPermissionControllerPackageName());
        ResolveInfo resolveInfo = packageManager.resolveService(intent, 0);
        return resolveInfo.getComponentInfo().getComponentName();
    }

    /**
+15 −12
Original line number Diff line number Diff line
@@ -147,6 +147,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C

        mLegacyRoleResolver = legacyRoleResolver;

        RoleControllerManager.initializeRemoteServiceComponentName(context);

        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
        mAppOpsManager = context.getSystemService(AppOpsManager.class);

@@ -231,7 +233,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
            // Run grants again
            Slog.i(LOG_TAG, "Granting default permissions...");
            CompletableFuture<Void> result = new CompletableFuture<>();
            getOrCreateControllerService(userId).grantDefaultRoles(FgThread.getExecutor(),
            getOrCreateController(userId).grantDefaultRoles(FgThread.getExecutor(),
                    successful -> {
                        if (successful) {
                            userState.setPackagesHash(packagesHash);
@@ -318,7 +320,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
    }

    @NonNull
    private RoleControllerManager getOrCreateControllerService(@UserIdInt int userId) {
    private RoleControllerManager getOrCreateController(@UserIdInt int userId) {
        synchronized (mLock) {
            RoleControllerManager controller = mControllers.get(userId);
            if (controller == null) {
@@ -330,7 +332,8 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                } catch (NameNotFoundException e) {
                    throw new RuntimeException(e);
                }
                controller = new RoleControllerManager(context, FgThread.getHandler());
                controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
                        FgThread.getHandler(), context);
                mControllers.put(userId, controller);
            }
            return controller;
@@ -474,7 +477,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
            Preconditions.checkNotNull(callback, "callback cannot be null");

            getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, flags,
            getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags,
                    callback);
        }

@@ -494,7 +497,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
            Preconditions.checkNotNull(callback, "callback cannot be null");

            getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName, flags,
            getOrCreateController(userId).onRemoveRoleHolder(roleName, packageName, flags,
                    callback);
        }

@@ -513,7 +516,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
            Preconditions.checkNotNull(callback, "callback cannot be null");

            getOrCreateControllerService(userId).onClearRoleHolders(roleName, flags, callback);
            getOrCreateController(userId).onClearRoleHolders(roleName, flags, callback);
        }

        @Override
@@ -738,10 +741,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                }
            });
            if (packageName != null) {
                getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
                getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
                        packageName, 0, callback);
            } else {
                getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
                getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
                        callback);
            }
            try {
@@ -762,10 +765,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                }
            });
            if (packageName != null) {
                getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
                getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
                        packageName, 0, callback);
            } else {
                getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
                getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
                        callback);
            }
        }
@@ -791,10 +794,10 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                callback.accept(successful);
            });
            if (packageName != null) {
                getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
                getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
                        packageName, 0, remoteCallback);
            } else {
                getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0,
                getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0,
                        remoteCallback);
            }
        }