From e7ed20c00a681e2a7d08f4050c4583cb1f8748a6 Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Mon, 14 Mar 2022 14:35:44 +0000 Subject: [PATCH] Prevent potential deadlock when sending pending intent in WCT Post send pending intent while applying window container transaction to prevent the potential deadlock between WindowManagerGlobalLock and ActivityMangerService lock. BYPASS_INCLUSIVE_LANGUAGE_REASON=using existing API. Bug: 223365463 Test: pass existing tests Test: manual check lock holding sequence and thread Change-Id: I80f4671758dc930aa25381247280d44cccf4560c --- .../server/wm/WindowOrganizerController.java | 60 +++++++++++-------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index d862012942353..044da3982e268 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -94,6 +94,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.function.IntSupplier; /** * Server side implementation for the interface for organizing windows @@ -810,26 +811,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID); final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid); - final Integer[] starterResult = {null}; - // startActivityFromRecents should not be called in lock. - mService.mH.post(() -> { - try { - starterResult[0] = mService.mTaskSupervisor.startActivityFromRecents( - caller.mPid, caller.mUid, taskId, safeOptions); - } catch (Throwable t) { - starterResult[0] = ActivityManager.START_CANCELED; - Slog.w(TAG, t); - } - synchronized (mGlobalLock) { - mGlobalLock.notifyAll(); - } - }); - while (starterResult[0] == null) { - try { - mGlobalLock.wait(); - } catch (InterruptedException ignored) { - } - } + waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents( + caller.mPid, caller.mUid, taskId, safeOptions)); break; } case HIERARCHY_OP_TYPE_PENDING_INTENT: { @@ -838,22 +821,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub mService.mContext.getContentResolver()) : null; - Bundle options = null; + ActivityOptions activityOptions = null; if (hop.getPendingIntent().isActivity()) { // Set the context display id as preferred for this activity launches, so that // it can land on caller's display. Or just brought the task to front at the // display where it was on since it has higher preference. - ActivityOptions activityOptions = hop.getLaunchOptions() != null + activityOptions = hop.getLaunchOptions() != null ? new ActivityOptions(hop.getLaunchOptions()) : ActivityOptions.makeBasic(); activityOptions.setCallerDisplayId(DEFAULT_DISPLAY); - options = activityOptions.toBundle(); } - - mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(), + final Bundle options = activityOptions != null ? activityOptions.toBundle() : null; + waitAsyncStart(() -> mService.mAmInternal.sendIntentSender( + hop.getPendingIntent().getTarget(), hop.getPendingIntent().getWhitelistToken(), 0 /* code */, hop.getActivityIntent(), resolvedType, null /* finishReceiver */, - null /* requiredPermission */, options); + null /* requiredPermission */, options)); break; } case HIERARCHY_OP_TYPE_START_SHORTCUT: { @@ -914,6 +897,31 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return effects; } + /** + * Post and wait for the result of the activity start to prevent potential deadlock against + * {@link WindowManagerGlobalLock}. + */ + private void waitAsyncStart(IntSupplier startActivity) { + final Integer[] starterResult = {null}; + mService.mH.post(() -> { + try { + starterResult[0] = startActivity.getAsInt(); + } catch (Throwable t) { + starterResult[0] = ActivityManager.START_CANCELED; + Slog.w(TAG, t); + } + synchronized (mGlobalLock) { + mGlobalLock.notifyAll(); + } + }); + while (starterResult[0] == null) { + try { + mGlobalLock.wait(); + } catch (InterruptedException ignored) { + } + } + } + private int sanitizeAndApplyHierarchyOp(WindowContainer container, WindowContainerTransaction.HierarchyOp hop) { final Task task = container.asTask();