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

Commit e7ed20c0 authored by Jerry Chang's avatar Jerry Chang
Browse files

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
parent 4bb44e08
Loading
Loading
Loading
Loading
+34 −26
Original line number Original line Diff line number Diff line
@@ -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();