Use quick path to start recents if the caller is trusted
To reduce latency that schedules on another thread with more
steps to process pending intent.
The quick path can only be used when the creator uid of
PendingIntent is recents itself, so the real caller is restricted
to be only from recents component (SystemUiProxy).
Bug: 275508603
Test: Capture trace when swiping up app to enter recent.
Change-Id: I1d817e52ba22296269cd651cf38d3606aab6d7b3
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index bfe2986..a6e5040 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -45,6 +45,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
@@ -554,7 +555,25 @@
.execute();
}
+ /**
+ * A quick path (skip general intent/task resolving) to start recents animation if the recents
+ * (or home) activity is available in background.
+ * @return {@code true} if the recents activity is moved to front.
+ */
boolean startExistingRecentsIfPossible(Intent intent, ActivityOptions options) {
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startExistingRecents");
+ if (startExistingRecents(intent, options)) {
+ return true;
+ }
+ // Else follow the standard launch procedure.
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ return false;
+ }
+
+ private boolean startExistingRecents(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()
@@ -563,6 +582,7 @@
final ActivityRecord r = rootTask.topRunningActivity();
if (r == null || r.isVisibleRequested() || !r.attachedToProcess()
|| !r.mActivityComponent.equals(intent.getComponent())
+ || !mService.isCallerRecents(r.getUid())
// Recents keeps invisible while device is locked.
|| r.mDisplayContent.isKeyguardLocked()) {
return false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 1f4606b..a0ea1c3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5753,23 +5753,6 @@
boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent,
BackgroundStartPrivileges backgroundStartPrivileges) {
assertPackageMatchesCallingUid(callingPackage);
- // A quick path (skip general intent/task resolving) to start recents animation if the
- // recents (or home) activity is available in background.
- if (options != null && options.getOriginalOptions() != null
- && options.getOriginalOptions().getTransientLaunch() && isCallerRecents(uid)) {
- try {
- synchronized (mGlobalLock) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "startExistingRecents");
- if (mActivityStartController.startExistingRecentsIfPossible(
- intent, options.getOriginalOptions())) {
- return ActivityManager.START_TASK_TO_FRONT;
- }
- // Else follow the standard launch procedure.
- }
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- }
return getActivityStartController().startActivityInPackage(uid, realCallingPid,
realCallingUid, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, options, userId, inTask,
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index cd42528..68b53c9 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -971,19 +971,30 @@
switch (type) {
case HIERARCHY_OP_TYPE_PENDING_INTENT: {
+ final Bundle launchOpts = hop.getLaunchOptions();
+ ActivityOptions activityOptions = launchOpts != null
+ ? new ActivityOptions(launchOpts) : null;
+ if (activityOptions != null && activityOptions.getTransientLaunch()
+ && mService.isCallerRecents(hop.getPendingIntent().getCreatorUid())) {
+ if (mService.getActivityStartController().startExistingRecentsIfPossible(
+ hop.getActivityIntent(), activityOptions)) {
+ // Start recents successfully.
+ break;
+ }
+ }
+
String resolvedType = hop.getActivityIntent() != null
? hop.getActivityIntent().resolveTypeIfNeeded(
mService.mContext.getContentResolver())
: null;
- ActivityOptions activityOptions = null;
if (hop.getPendingIntent().isActivity()) {
// 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
// display where it was on since it has higher preference.
- activityOptions = hop.getLaunchOptions() != null
- ? new ActivityOptions(hop.getLaunchOptions())
- : ActivityOptions.makeBasic();
+ if (activityOptions == null) {
+ activityOptions = ActivityOptions.makeBasic();
+ }
activityOptions.setCallerDisplayId(DEFAULT_DISPLAY);
}
final Bundle options = activityOptions != null ? activityOptions.toBundle() : null;