diff options
5 files changed, 74 insertions, 3 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index a78dbd6bbe60..9be93404dcf1 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -19,7 +19,9 @@ package com.android.server.wm; import static android.app.ActivityManager.START_CANCELED; import static android.app.ActivityManager.START_SUCCESS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL; @@ -29,6 +31,7 @@ import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.IApplicationThread; import android.content.ComponentName; @@ -46,6 +49,7 @@ import android.provider.Settings; import android.util.Slog; import android.util.SparseArray; import android.view.RemoteAnimationAdapter; +import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; @@ -536,6 +540,42 @@ public class ActivityStartController { .execute(); } + boolean startExistingRecentsIfPossible(Intent intent, ActivityOptions options) { + final int activityType = mService.getRecentTasks().getRecentsComponent() + .equals(intent.getComponent()) ? ACTIVITY_TYPE_RECENTS : ACTIVITY_TYPE_HOME; + final Task rootTask = mService.mRootWindowContainer.getDefaultTaskDisplayArea() + .getRootTask(WINDOWING_MODE_UNDEFINED, activityType); + if (rootTask == null) return false; + final ActivityRecord r = rootTask.topRunningActivity(); + if (r == null || r.mVisibleRequested || !r.attachedToProcess() + || !r.mActivityComponent.equals(intent.getComponent()) + // Recents keeps invisible while device is locked. + || r.mDisplayContent.isKeyguardLocked()) { + return false; + } + mService.mRootWindowContainer.startPowerModeLaunchIfNeeded(true /* forceSend */, r); + final ActivityMetricsLogger.LaunchingState launchingState = + mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent); + final Task task = r.getTask(); + mService.deferWindowLayout(); + try { + task.mTransitionController.requestTransitionIfNeeded(WindowManager.TRANSIT_TO_FRONT, + 0 /* flags */, task, task /* readyGroupRef */, + options.getRemoteTransition(), null /* displayChange */); + r.mTransitionController.setTransientLaunch(r, + TaskDisplayArea.getRootTaskAbove(rootTask)); + task.moveToFront("startExistingRecents"); + task.mInResumeTopActivity = true; + task.resumeTopActivity(null /* prev */, options, true /* deferPause */); + mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, + ActivityManager.START_TASK_TO_FRONT, false, r, options); + } finally { + task.mInResumeTopActivity = false; + mService.continueWindowLayout(); + } + return true; + } + void registerRemoteAnimationForNextActivityStart(String packageName, RemoteAnimationAdapter adapter, @Nullable IBinder launchCookie) { mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter, launchCookie); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 7bc551b2aacc..50e7299edef4 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1231,6 +1231,28 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Nullable String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) { + + final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions); + // A quick path (skip general intent/task resolving) to start recents animation if the + // recents (or home) activity is available in background. + if (opts != null && opts.getOriginalOptions().getTransientLaunch() + && isCallerRecents(Binder.getCallingUid())) { + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "startExistingRecents"); + if (mActivityStartController.startExistingRecentsIfPossible( + intent, opts.getOriginalOptions())) { + return ActivityManager.START_TASK_TO_FRONT; + } + // Else follow the standard launch procedure. + } + } finally { + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + Binder.restoreCallingIdentity(origId); + } + } + assertPackageMatchesCallingUid(callingPackage); enforceNotIsolatedCaller("startActivityAsUser"); if (Process.isSdkSandboxUid(Binder.getCallingUid())) { @@ -1257,7 +1279,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { .setRequestCode(requestCode) .setStartFlags(startFlags) .setProfilerInfo(profilerInfo) - .setActivityOptions(bOptions) + .setActivityOptions(opts) .setUserId(userId) .execute(); diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java index e3de18b1ebc7..b2840b26ac8d 100644 --- a/services/core/java/com/android/server/wm/AsyncRotationController.java +++ b/services/core/java/com/android/server/wm/AsyncRotationController.java @@ -120,7 +120,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume } else { mTransitionOp = OP_CHANGE; } - } else if (transitionType != WindowManager.TRANSIT_NONE) { + } else if (displayContent.mTransitionController.isShellTransitionsEnabled()) { mTransitionOp = OP_APP_SWITCH; } else { mTransitionOp = OP_LEGACY; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ad3b8ee119d3..e814f2779dba 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1683,7 +1683,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return false; } } - if (r.isState(RESUMED) && !r.getRootTask().mInResumeTopActivity) { + if (r.isState(RESUMED) && !r.getTask().mInResumeTopActivity) { // If the activity is executing or has done the lifecycle callback, use normal // rotation animation so the display info can be updated immediately (see // updateDisplayAndOrientation). This prevents a compatibility issue such as diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java index baa31a073dd2..2879e33fb71a 100644 --- a/services/core/java/com/android/server/wm/SafeActivityOptions.java +++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.Manifest.permission.CONTROL_KEYGUARD; import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; +import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; import static android.Manifest.permission.STATUS_BAR_SERVICE; import static android.app.ActivityTaskManager.INVALID_TASK_ID; @@ -247,6 +248,14 @@ public class SafeActivityOptions { throw new SecurityException(msg); } } + if (options.getTransientLaunch() && !supervisor.mRecentTasks.isCallerRecents(callingUid) + && ActivityTaskManagerService.checkPermission( + MANAGE_ACTIVITY_TASKS, callingPid, callingUid) == PERMISSION_DENIED) { + final String msg = "Permission Denial: starting transient launch from " + callerApp + + ", pid=" + callingPid + ", uid=" + callingUid; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } // Check if the caller is allowed to launch on the specified display area. final WindowContainerToken daToken = options.getLaunchTaskDisplayArea(); final TaskDisplayArea taskDisplayArea = daToken != null |