From cd9f253cc46a3f3dc6cdce87837839dc379c14dc Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Mon, 16 Nov 2020 10:10:29 -0800 Subject: [PATCH] Fix deadlock in getOneTimePermissionUserManager(). The OneTimePermissionUserManager constructor may acquire the package manager lock inside, so we cannot call it while holding our permission lock. Fixes: 173097873 Test: presubmit Change-Id: I7178bc0a642d6c42dfc9edf855dce72deaa1e699 --- .../permission/PermissionManagerService.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index ff661a8860d09..c03b98df326af 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -3369,16 +3369,28 @@ public class PermissionManagerService extends IPermissionManager.Stub { SystemConfig.getInstance().getSplitPermissions()); } + @NonNull private OneTimePermissionUserManager getOneTimePermissionUserManager(@UserIdInt int userId) { OneTimePermissionUserManager oneTimePermissionUserManager; synchronized (mLock) { - oneTimePermissionUserManager = - mOneTimePermissionUserManagers.get(userId); + oneTimePermissionUserManager = mOneTimePermissionUserManagers.get(userId); if (oneTimePermissionUserManager != null) { return oneTimePermissionUserManager; } - oneTimePermissionUserManager = new OneTimePermissionUserManager( - mContext.createContextAsUser(UserHandle.of(userId), /*flags*/ 0)); + } + // We cannot create a new instance of OneTimePermissionUserManager while holding our own + // lock, which may lead to a deadlock with the package manager lock. So we do it in a + // retry-like way, and just discard the newly created instance if someone else managed to be + // a little bit faster than us when we dropped our own lock. + final OneTimePermissionUserManager newOneTimePermissionUserManager = + new OneTimePermissionUserManager(mContext.createContextAsUser(UserHandle.of(userId), + /*flags*/ 0)); + synchronized (mLock) { + oneTimePermissionUserManager = mOneTimePermissionUserManagers.get(userId); + if (oneTimePermissionUserManager != null) { + return oneTimePermissionUserManager; + } + oneTimePermissionUserManager = newOneTimePermissionUserManager; mOneTimePermissionUserManagers.put(userId, oneTimePermissionUserManager); } oneTimePermissionUserManager.registerUninstallListener();