Merge "Do not lock when calling startActivityFromRecents" into sc-v2-dev

This commit is contained in:
Riddle Hsu
2021-09-28 08:33:38 +00:00
committed by Android (Google) Code Review
4 changed files with 123 additions and 84 deletions

View File

@@ -1732,10 +1732,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(bOptions);
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
return mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, taskId,
safeOptions);
}
return mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, taskId,
safeOptions);
} finally {
Binder.restoreCallingIdentity(origId);
}

View File

@@ -2474,102 +2474,126 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
}
/**
* Start the given task from the recent tasks. Do not hold WM global lock when calling this
* method to avoid potential deadlock or permission deny by UriGrantsManager when resolving
* activity (see {@link ActivityStarter.Request#resolveActivity} and
* {@link com.android.server.am.ContentProviderHelper#checkContentProviderUriPermission}).
*
* @return The result code of starter.
*/
int startActivityFromRecents(int callingPid, int callingUid, int taskId,
SafeActivityOptions options) {
Task task = null;
final Task task;
final int taskCallingUid;
final String callingPackage;
final String callingFeatureId;
final Intent intent;
final int userId;
int activityType = ACTIVITY_TYPE_UNDEFINED;
int windowingMode = WINDOWING_MODE_UNDEFINED;
final ActivityOptions activityOptions = options != null
? options.getOptions(this)
: null;
boolean moveHomeTaskForward = true;
if (activityOptions != null) {
activityType = activityOptions.getLaunchActivityType();
windowingMode = activityOptions.getLaunchWindowingMode();
if (activityOptions.freezeRecentTasksReordering()
&& mRecentTasks.isCallerRecents(callingUid)) {
mRecentTasks.setFreezeTaskListReordering();
synchronized (mService.mGlobalLock) {
int activityType = ACTIVITY_TYPE_UNDEFINED;
if (activityOptions != null) {
activityType = activityOptions.getLaunchActivityType();
final int windowingMode = activityOptions.getLaunchWindowingMode();
if (activityOptions.freezeRecentTasksReordering()
&& mRecentTasks.isCallerRecents(callingUid)) {
mRecentTasks.setFreezeTaskListReordering();
}
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| activityOptions.getLaunchRootTask() != null) {
// Don't move home activity forward if we are launching into primary split or
// there is a launch root set.
moveHomeTaskForward = false;
}
}
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| activityOptions.getLaunchRootTask() != null) {
// Don't move home activity forward if we are launching into primary split or there
// is a launch root set.
moveHomeTaskForward = false;
}
}
if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
throw new IllegalArgumentException("startActivityFromRecents: Task "
+ taskId + " can't be launch in the home/recents root task.");
}
mService.deferWindowLayout();
try {
task = mRootWindowContainer.anyTaskForId(taskId,
MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
if (task == null) {
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
"startActivityFromRecents: Task " + taskId + " not found.");
if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
throw new IllegalArgumentException("startActivityFromRecents: Task "
+ taskId + " can't be launch in the home/recents root task.");
}
if (moveHomeTaskForward) {
// We always want to return to the home activity instead of the recents activity
// from whatever is started from the recents activity, so move the home root task
// forward.
// TODO (b/115289124): Multi-display supports for recents.
mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront(
"startActivityFromRecents");
}
// If the user must confirm credentials (e.g. when first launching a work app and the
// Work Challenge is present) let startActivityInPackage handle the intercepting.
if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
&& task.getRootActivity() != null) {
final ActivityRecord targetActivity = task.getTopNonFinishingActivity();
mRootWindowContainer.startPowerModeLaunchIfNeeded(
true /* forceSend */, targetActivity);
final LaunchingState launchingState =
mActivityMetricsLogger.notifyActivityLaunching(task.intent);
try {
mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
task.mTaskId, 0, options);
// Apply options to prevent pendingOptions be taken when scheduling activity
// lifecycle transaction to make sure the override pending app transition will
// be applied immediately.
targetActivity.applyOptionsAnimation();
} finally {
mActivityMetricsLogger.notifyActivityLaunched(launchingState,
START_TASK_TO_FRONT, false /* newActivityCreated */, targetActivity,
activityOptions);
boolean shouldStartActivity = false;
mService.deferWindowLayout();
try {
task = mRootWindowContainer.anyTaskForId(taskId,
MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
if (task == null) {
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
"startActivityFromRecents: Task " + taskId + " not found.");
}
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,
task.getRootTask());
if (moveHomeTaskForward) {
// We always want to return to the home activity instead of the recents
// activity from whatever is started from the recents activity, so move
// the home root task forward.
// TODO (b/115289124): Multi-display supports for recents.
mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront(
"startActivityFromRecents");
}
// As it doesn't go to ActivityStarter.executeRequest() path, we need to resume
// app switching here also.
mService.resumeAppSwitches();
// If the user must confirm credentials (e.g. when first launching a work
// app and the Work Challenge is present) let startActivityInPackage handle
// the intercepting.
if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
&& task.getRootActivity() != null) {
final ActivityRecord targetActivity = task.getTopNonFinishingActivity();
return ActivityManager.START_TASK_TO_FRONT;
mRootWindowContainer.startPowerModeLaunchIfNeeded(
true /* forceSend */, targetActivity);
final LaunchingState launchingState =
mActivityMetricsLogger.notifyActivityLaunching(task.intent);
try {
mService.moveTaskToFrontLocked(null /* appThread */,
null /* callingPackage */, task.mTaskId, 0, options);
// Apply options to prevent pendingOptions be taken when scheduling
// activity lifecycle transaction to make sure the override pending app
// transition will be applied immediately.
targetActivity.applyOptionsAnimation();
} finally {
mActivityMetricsLogger.notifyActivityLaunched(launchingState,
START_TASK_TO_FRONT, false /* newActivityCreated */,
targetActivity, activityOptions);
}
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,
task.getRootTask());
// As it doesn't go to ActivityStarter.executeRequest() path, we need to resume
// app switching here also.
mService.resumeAppSwitches();
return ActivityManager.START_TASK_TO_FRONT;
}
// The task is empty or needs to show the confirmation for credential.
shouldStartActivity = true;
} finally {
if (!shouldStartActivity) {
mService.continueWindowLayout();
}
}
taskCallingUid = task.mCallingUid;
callingPackage = task.mCallingPackage;
callingFeatureId = task.mCallingFeatureId;
intent = task.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
userId = task.mUserId;
return mService.getActivityStartController().startActivityInPackage(task.mCallingUid,
}
// ActivityStarter will acquire the lock where the places need, so execute the request
// outside of the lock.
try {
return mService.getActivityStartController().startActivityInPackage(taskCallingUid,
callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null,
null, 0, 0, options, userId, task, "startActivityFromRecents",
false /* validateIncomingUser */, null /* originatingPendingIntent */,
false /* allowBackgroundActivityStart */);
} finally {
mService.continueWindowLayout();
synchronized (mService.mGlobalLock) {
mService.continueWindowLayout();
}
}
}

View File

@@ -35,10 +35,10 @@ import android.os.UserHandle;
*/
class AppTaskImpl extends IAppTask.Stub {
private static final String TAG = "AppTaskImpl";
private ActivityTaskManagerService mService;
private final ActivityTaskManagerService mService;
private int mTaskId;
private int mCallingUid;
private final int mTaskId;
private final int mCallingUid;
public AppTaskImpl(ActivityTaskManagerService service, int taskId, int callingUid) {
mService = service;
@@ -113,9 +113,9 @@ class AppTaskImpl extends IAppTask.Stub {
return;
}
}
mService.mTaskSupervisor.startActivityFromRecents(callingPid,
callingUid, mTaskId, null);
}
mService.mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, mTaskId,
null /* options */);
} finally {
Binder.restoreCallingIdentity(origId);
}

View File

@@ -318,7 +318,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
* @param caller Info about the calling process.
*/
private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
@Nullable Transition transition, @Nullable CallerInfo caller) {
@Nullable Transition transition, @NonNull CallerInfo caller) {
int effects = 0;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
@@ -540,7 +540,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
@Nullable CallerInfo caller, @Nullable IBinder errorCallbackToken,
@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
@Nullable ITaskFragmentOrganizer organizer) {
final int type = hop.getType();
switch (type) {
@@ -628,11 +628,28 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final int taskId = launchOpts.getInt(
WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
final SafeActivityOptions safeOptions = caller != null
? SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid)
: SafeActivityOptions.fromBundle(launchOpts);
mService.mTaskSupervisor.startActivityFromRecents(caller.mPid, caller.mUid,
taskId, safeOptions);
final SafeActivityOptions safeOptions =
SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
final Integer[] starterResult = { null };
// startActivityFromRecents should not be called in lock.
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;
case HIERARCHY_OP_TYPE_PENDING_INTENT:
String resolvedType = hop.getActivityIntent() != null