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

Commit 006ee3fe authored by Vishnu Nair's avatar Vishnu Nair
Browse files

AM: Fix deadlock when calling AMS from ATMS/WM

Instead of calling AMS synchronously, release the wm lock and pass it to AMS. Wait for AMS to
notify us when its done.

Fixes: 119265867, 119275681
Test: adb shell am start-activity -S -W com.google.android.apps.maps/com.google.android.maps.MapsActivity
Test: atest CtsSampleHostTestCases
Change-Id: Idc2895c14ccd92524e88ce3dda24b3d0e8dce2c1
parent 8e3554a1
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -277,7 +277,12 @@ public abstract class ActivityManagerInternal {
    public abstract void startProcess(String processName, ApplicationInfo info,
            boolean knownToBeDead, String hostingType, ComponentName hostingName);

    /** Starts up the starting activity process for debugging if needed. */
    /** Starts up the starting activity process for debugging if needed.
     * This function needs to be called synchronously from WindowManager context so the caller
     * passes a lock {@code wmLock} and waits to be notified.
     *
     * @param wmLock calls {@code notify} on the object to wake up the caller.
    */
    public abstract void setDebugFlagsForStartingActivity(ActivityInfo aInfo, int startFlags,
            ProfilerInfo profilerInfo);
            ProfilerInfo profilerInfo, Object wmLock);
}
+21 −30
Original line number Diff line number Diff line
@@ -3046,36 +3046,19 @@ public class ActivityManagerService extends IActivityManager.Stub
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        synchronized (this) {
            /**
             * Flags like {@link android.app.ActivityManager#START_FLAG_DEBUG} maybe be set on this
             * call when called/invoked from the shell command. To avoid deadlock, we go ahead and
             * acquire the AMS lock now since ATMS will need to synchronously call back into AMS
             * later to modify process settings due to the flags.
             * TODO(b/80414790): Investigate a better way of untangling this.
             */
            return mActivityTaskManager.startActivityAsUser(caller, callingPackage, intent,
                    resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
                    bOptions, userId);
    }
    }
    WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        synchronized (this) {
            /**
             * Flags like {@link android.app.ActivityManager#START_FLAG_DEBUG} maybe be set on this
             * call when called/invoked from the shell command. To avoid deadlock, we go ahead and
             * acquire the AMS lock now since ATMS will need to synchronously call back into AMS
             * later to modify process settings due to the flags.
             * TODO(b/80414790): Investigate a better way of untangling this.
             */
            return mActivityTaskManager.startActivityAndWait(caller, callingPackage, intent,
                    resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo,
                    bOptions, userId);
    }
    }
    @Override
    public final int startActivityFromRecents(int taskId, Bundle bOptions) {
@@ -19166,8 +19149,14 @@ public class ActivityManagerService extends IActivityManager.Stub
        @Override
        public void setDebugFlagsForStartingActivity(ActivityInfo aInfo, int startFlags,
                ProfilerInfo profilerInfo) {
                ProfilerInfo profilerInfo, Object wmLock) {
            synchronized (ActivityManagerService.this) {
                /**
                 * This function is called from the window manager context and needs to be executed
                 * synchronously.  To avoid deadlock, we pass a message to AMS to execute the
                 * function and notify the passed in lock when it has been completed.
                 */
                synchronized (wmLock) {
                    if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
                        setDebugApp(aInfo.processName, true, false);
                    }
@@ -19183,6 +19172,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                    if (profilerInfo != null) {
                        setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
                    }
                    wmLock.notify();
                }
            }
        }
    }
+18 −9
Original line number Diff line number Diff line
@@ -1272,15 +1272,24 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            if (!aInfo.processName.equals("system")) {
                if ((startFlags & (START_FLAG_DEBUG | START_FLAG_NATIVE_DEBUGGING
                        | START_FLAG_TRACK_ALLOCATION)) != 0 || profilerInfo != null) {
                    /**
                     * Assume safe to call into AMS synchronously because the call that set these
                     * flags should have originated from AMS which will already have its lock held.
                     * @see ActivityManagerService#startActivityAndWait(IApplicationThread, String,
                     * Intent, String, IBinder, String, int, int, ProfilerInfo, Bundle, int)
                     * TODO(b/80414790): Investigate a better way of untangling this.
                     */
                    mService.mAmInternal.setDebugFlagsForStartingActivity(
                            aInfo, startFlags, profilerInfo);

                     // Mimic an AMS synchronous call by passing a message to AMS and wait for AMS
                     // to notify us that the task has completed.
                     // TODO(b/80414790) look into further untangling for the situation where the
                     // caller is on the same thread as the handler we are posting to.
                    synchronized (mService.mGlobalLock) {
                        // Post message to AMS.
                        final Message msg = PooledLambda.obtainMessage(
                                ActivityManagerInternal::setDebugFlagsForStartingActivity,
                                mService.mAmInternal, aInfo, startFlags, profilerInfo,
                                mService.mGlobalLock);
                        mService.mH.sendMessage(msg);
                        try {
                            mService.mGlobalLock.wait();
                        } catch (InterruptedException ignore) {

                        }
                    }
                }
            }
            final String intentLaunchToken = intent.getLaunchToken();