Merge "Prevent potential deadlock when sending pending intent in WCT" into tm-dev am: ec8b28e50d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17214344

Change-Id: I873af9e14b8b0f41d6c79e1fe05b1f48375d5584
This commit is contained in:
Jerry Chang
2022-03-21 09:16:25 +00:00
committed by Automerger Merge Worker

View File

@@ -94,6 +94,7 @@ import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.IntSupplier;
/** /**
* Server side implementation for the interface for organizing windows * 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); launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
final SafeActivityOptions safeOptions = final SafeActivityOptions safeOptions =
SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid); SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
final Integer[] starterResult = {null}; waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
// startActivityFromRecents should not be called in lock. caller.mPid, caller.mUid, taskId, safeOptions));
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) {
}
}
break; break;
} }
case HIERARCHY_OP_TYPE_PENDING_INTENT: { case HIERARCHY_OP_TYPE_PENDING_INTENT: {
@@ -838,22 +821,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mService.mContext.getContentResolver()) mService.mContext.getContentResolver())
: null; : null;
Bundle options = null; ActivityOptions activityOptions = null;
if (hop.getPendingIntent().isActivity()) { if (hop.getPendingIntent().isActivity()) {
// Set the context display id as preferred for this activity launches, so that // 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 // 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. // display where it was on since it has higher preference.
ActivityOptions activityOptions = hop.getLaunchOptions() != null activityOptions = hop.getLaunchOptions() != null
? new ActivityOptions(hop.getLaunchOptions()) ? new ActivityOptions(hop.getLaunchOptions())
: ActivityOptions.makeBasic(); : ActivityOptions.makeBasic();
activityOptions.setCallerDisplayId(DEFAULT_DISPLAY); activityOptions.setCallerDisplayId(DEFAULT_DISPLAY);
options = activityOptions.toBundle();
} }
final Bundle options = activityOptions != null ? activityOptions.toBundle() : null;
mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(), waitAsyncStart(() -> mService.mAmInternal.sendIntentSender(
hop.getPendingIntent().getTarget(),
hop.getPendingIntent().getWhitelistToken(), 0 /* code */, hop.getPendingIntent().getWhitelistToken(), 0 /* code */,
hop.getActivityIntent(), resolvedType, null /* finishReceiver */, hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
null /* requiredPermission */, options); null /* requiredPermission */, options));
break; break;
} }
case HIERARCHY_OP_TYPE_START_SHORTCUT: { case HIERARCHY_OP_TYPE_START_SHORTCUT: {
@@ -914,6 +897,31 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
return effects; 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, private int sanitizeAndApplyHierarchyOp(WindowContainer container,
WindowContainerTransaction.HierarchyOp hop) { WindowContainerTransaction.HierarchyOp hop) {
final Task task = container.asTask(); final Task task = container.asTask();