Fix potential deadlock in transactions

It was possible to hit a deadlock scenario when using the
waitAsyncStart utility. Since that was using the main handler
for unlocked work, if the transaction was applied from the
main handler thread, it would deadlock (this happens when
transactions are queued-up on syncengine). This adds a check
and will run the uncommon queued launches on anim-thread
(which is 1 higher priority).

This also has the waitAsyncStart function actually return
the result so that we can properly observe the effects of
a PendingIntent

Bug: 271317661
Bug: 267738124
Test: System still runs and tests pass.
Change-Id: If99668b71cafe016b1ab2aad501c53d246e2877d
This commit is contained in:
Evan Rosky
2023-03-01 18:35:04 -08:00
parent f362c2d74b
commit c8ecacc046

View File

@@ -74,7 +74,9 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.AndroidRuntimeException;
@@ -998,11 +1000,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
activityOptions.setCallerDisplayId(DEFAULT_DISPLAY);
}
final Bundle options = activityOptions != null ? activityOptions.toBundle() : null;
waitAsyncStart(() -> mService.mAmInternal.sendIntentSender(
int res = waitAsyncStart(() -> mService.mAmInternal.sendIntentSender(
hop.getPendingIntent().getTarget(),
hop.getPendingIntent().getWhitelistToken(), 0 /* code */,
hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
null /* requiredPermission */, options));
if (ActivityManager.isStartResultSuccessful(res)) {
effects |= TRANSACT_EFFECTS_LIFECYCLE;
}
break;
}
case HIERARCHY_OP_TYPE_START_SHORTCUT: {
@@ -1353,9 +1358,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
* Post and wait for the result of the activity start to prevent potential deadlock against
* {@link WindowManagerGlobalLock}.
*/
private void waitAsyncStart(IntSupplier startActivity) {
private int waitAsyncStart(IntSupplier startActivity) {
final Integer[] starterResult = {null};
mService.mH.post(() -> {
final Handler handler = (Looper.myLooper() == mService.mH.getLooper())
// uncommon case where a queued transaction is trying to start an activity. We can't
// post to our own thread and wait (otherwise we deadlock), so use anim thread
// instead (which is 1 higher priority).
? mService.mWindowManager.mAnimationHandler
// Otherwise just put it on main handler
: mService.mH;
handler.post(() -> {
try {
starterResult[0] = startActivity.getAsInt();
} catch (Throwable t) {
@@ -1372,6 +1384,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
} catch (InterruptedException ignored) {
}
}
return starterResult[0];
}
private int sanitizeAndApplyHierarchyOp(WindowContainer container,