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

Commit ec8b28e5 authored by Jerry Chang's avatar Jerry Chang Committed by Android (Google) Code Review
Browse files

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

parents 8c1fad0d e7ed20c0
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();