Merge "Make ActivityStarter single use."

This commit is contained in:
Bryce Lee
2017-12-04 15:29:31 +00:00
committed by Android (Google) Code Review
10 changed files with 769 additions and 394 deletions

View File

@@ -44,7 +44,9 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
@@ -632,7 +634,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final ActivityStackSupervisor mStackSupervisor;
private final KeyguardController mKeyguardController;
final ActivityStarter mActivityStarter;
private final ActivityStartController mActivityStartController;
final ClientLifecycleManager mLifecycleManager;
@@ -1361,7 +1363,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this") boolean mCallFinishBooting = false;
@GuardedBy("this") boolean mBootAnimationComplete = false;
@GuardedBy("this") boolean mLaunchWarningShown = false;
@GuardedBy("this") boolean mCheckedForSetup = false;
private @GuardedBy("this") boolean mCheckedForSetup = false;
final Context mContext;
@@ -1707,7 +1709,6 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int SHOW_UID_ERROR_UI_MSG = 14;
static final int SHOW_FINGERPRINT_ERROR_UI_MSG = 15;
static final int PROC_START_TIMEOUT_MSG = 20;
static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
static final int KILL_APPLICATION_MSG = 22;
static final int FINALIZE_PENDING_INTENT_MSG = 23;
static final int POST_HEAVY_NOTIFICATION_MSG = 24;
@@ -2077,11 +2078,6 @@ public class ActivityManagerService extends IActivityManager.Stub
processContentProviderPublishTimedOutLocked(app);
}
} break;
case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
synchronized (ActivityManagerService.this) {
mActivityStarter.doPendingActivityLaunchesLocked(true);
}
} break;
case KILL_APPLICATION_MSG: {
synchronized (ActivityManagerService.this) {
final int appId = msg.arg1;
@@ -2677,7 +2673,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mContext = mInjector.getContext();
mUiContext = null;
GL_ES_VERSION = 0;
mActivityStarter = null;
mActivityStartController = null;
mAppErrors = null;
mAppWarnings = null;
mAppOpsService = mInjector.getAppOpsService(null, null);
@@ -2801,7 +2797,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mTaskChangeNotificationController =
new TaskChangeNotificationController(this, mStackSupervisor, mHandler);
mActivityStarter = new ActivityStarter(this);
mActivityStartController = new ActivityStartController(this);
mRecentTasks = createRecentTasks();
mStackSupervisor.setRecentTasks(mRecentTasks);
mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler);
@@ -4121,7 +4117,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// For ANR debugging to verify if the user activity is the one that actually
// launched.
final String myReason = reason + ":" + userId + ":" + resolvedUserId;
mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
mActivityStartController.startHomeActivity(intent, aInfo, myReason);
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
@@ -4154,49 +4150,12 @@ public class ActivityManagerService extends IActivityManager.Stub
return ai;
}
/**
* Starts the "new version setup screen" if appropriate.
*/
void startSetupActivityLocked() {
// Only do this once per boot.
if (mCheckedForSetup) {
return;
}
boolean getCheckedForSetup() {
return mCheckedForSetup;
}
// We will show this screen if the current one is a different
// version than the last one shown, and we are not running in
// low-level factory test mode.
final ContentResolver resolver = mContext.getContentResolver();
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL &&
Settings.Global.getInt(resolver,
Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
mCheckedForSetup = true;
// See if we should be showing the platform update setup UI.
final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
final List<ResolveInfo> ris = mContext.getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
if (!ris.isEmpty()) {
final ResolveInfo ri = ris.get(0);
String vers = ri.activityInfo.metaData != null
? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
: null;
if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
vers = ri.activityInfo.applicationInfo.metaData.getString(
Intent.METADATA_SETUP_VERSION);
}
String lastVers = Settings.Secure.getString(
resolver, Settings.Secure.LAST_SETUP_SHOWN);
if (vers != null && !vers.equals(lastVers)) {
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name));
mActivityStarter.startActivityLocked(null, intent, null /*ephemeralIntent*/,
null, ri.activityInfo, null /*rInfo*/, null, null, null, null, 0, 0, 0,
null, 0, 0, 0, null, false, false, null, null, "startSetupActivity");
}
}
}
void setCheckedForSetup(boolean checked) {
mCheckedForSetup = checked;
}
CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
@@ -4562,8 +4521,8 @@ public class ActivityManagerService extends IActivityManager.Stub
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
return mActivityStartController.startActivityMayWait(caller, -1, callingPackage,
intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, "startActivityAsUser");
}
@@ -4625,10 +4584,10 @@ public class ActivityManagerService extends IActivityManager.Stub
// TODO: Switch to user app stacks here.
try {
int ret = mActivityStarter.startActivityMayWait(null, targetUid, targetPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
null, null, bOptions, ignoreTargetSecurity, userId, null,
"startActivityAsCaller");
int ret = mActivityStartController.startActivityMayWait(null, targetUid,
targetPackage, intent, resolvedType, null, null, resultTo, resultWho,
requestCode, startFlags, null, null, null, bOptions, ignoreTargetSecurity,
userId, null, "startActivityAsCaller");
return ret;
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.
@@ -4655,9 +4614,9 @@ public class ActivityManagerService extends IActivityManager.Stub
userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
WaitResult res = new WaitResult();
// TODO: Switch to user app stacks here.
mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
bOptions, false, userId, null, "startActivityAndWait");
mActivityStartController.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, res, null, bOptions, false, userId, null, "startActivityAndWait");
return res;
}
@@ -4669,9 +4628,9 @@ public class ActivityManagerService extends IActivityManager.Stub
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivityWithConfig", null);
// TODO: Switch to user app stacks here.
int ret = mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
null, null, config, bOptions, false, userId, null, "startActivityWithConfig");
int ret = mActivityStartController.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null, null,
config, bOptions, false, userId, null, "startActivityWithConfig");
return ret;
}
@@ -4718,9 +4677,9 @@ public class ActivityManagerService extends IActivityManager.Stub
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ALLOW_FULL_ONLY, "startVoiceActivity", null);
// TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
null, bOptions, false, userId, null, "startVoiceActivity");
return mActivityStartController.startActivityMayWait(null, callingUid, callingPackage,
intent, resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo,
null, null, bOptions, false, userId, null, "startVoiceActivity");
}
@Override
@@ -4729,9 +4688,9 @@ public class ActivityManagerService extends IActivityManager.Stub
enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ALLOW_FULL_ONLY, "startAssistantActivity", null);
return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
resolvedType, null, null, null, null, 0, 0, null, null, null, bOptions, false,
userId, null, "startAssistantActivity");
return mActivityStartController.startActivityMayWait(null, callingUid, callingPackage,
intent, resolvedType, null, null, null, null, 0, 0, null, null, null, bOptions,
false, userId, null, "startAssistantActivity");
}
@Override
@@ -4771,9 +4730,9 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(recentsComponent);
intent.putExtras(options);
return mActivityStarter.startActivityMayWait(null, recentsUid, recentsPackage,
intent, null, null, null, null, null, 0, 0, null, null, null, activityOptions,
false, userId, null, "startRecentsActivity");
return mActivityStartController.startActivityMayWait(null, recentsUid,
recentsPackage, intent, null, null, null, null, null, 0, 0, null, null,
null, activityOptions, false, userId, null, "startRecentsActivity");
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4946,7 +4905,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final long origId = Binder.clearCallingIdentity();
int res = mActivityStarter.startActivityLocked(r.app.thread, intent,
int res = mActivityStartController.startActivity(r.app.thread, intent,
null /*ephemeralIntent*/, r.resolvedType, aInfo, null /*rInfo*/, null,
null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1,
r.launchedFromUid, r.launchedFromPackage, -1, r.launchedFromUid, 0, options,
@@ -4976,20 +4935,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
final int startActivityInPackage(int uid, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId,
TaskRecord inTask, String reason) {
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
// TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(null, uid, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
null, null, null, bOptions, false, userId, inTask, reason);
}
@Override
public final int startActivities(IApplicationThread caller, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
@@ -4999,21 +4944,8 @@ public class ActivityManagerService extends IActivityManager.Stub
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, reason, null);
// TODO: Switch to user app stacks here.
int ret = mActivityStarter.startActivities(caller, -1, callingPackage, intents,
resolvedTypes, resultTo, bOptions, userId, reason);
return ret;
}
final int startActivitiesInPackage(int uid, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo,
Bundle bOptions, int userId) {
final String reason = "startActivityInPackage";
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, reason, null);
// TODO: Switch to user app stacks here.
int ret = mActivityStarter.startActivities(null, uid, callingPackage, intents, resolvedTypes,
resultTo, bOptions, userId, reason);
int ret = mActivityStartController.startActivities(caller, -1, callingPackage,
intents, resolvedTypes, resultTo, bOptions, userId, reason);
return ret;
}
@@ -6667,7 +6599,7 @@ public class ActivityManagerService extends IActivityManager.Stub
ProcessList.INVALID_ADJ, callerWillRestart, true, doit, evenPersistent,
packageName == null ? ("stop user " + userId) : ("stop " + packageName));
didSomething |= mActivityStarter.clearPendingActivityLaunchesLocked(packageName);
didSomething |= mActivityStartController.clearPendingActivityLaunches(packageName);
if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
packageName, null, doit, evenPersistent, userId)) {
@@ -11755,6 +11687,10 @@ public class ActivityManagerService extends IActivityManager.Stub
return AppGlobals.getPackageManager();
}
ActivityStartController getActivityStartController() {
return mActivityStartController;
}
PackageManagerInternal getPackageManagerInternalLocked() {
if (mPackageManagerInt == null) {
mPackageManagerInt = LocalServices.getService(PackageManagerInternal.class);
@@ -12604,7 +12540,16 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
final long ident = Binder.clearCallingIdentity();
try {
mActivityStarter.startConfirmCredentialIntent(intent, options);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
FLAG_ACTIVITY_TASK_ON_HOME);
ActivityOptions activityOptions = options != null
? new ActivityOptions(options)
: ActivityOptions.makeBasic();
activityOptions.setLaunchTaskId(
mStackSupervisor.getHomeActivity().getTask().taskId);
mContext.startActivityAsUser(intent, activityOptions.toBundle(),
UserHandle.CURRENT);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -12623,9 +12568,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
+ APP_SWITCH_DELAY_TIME;
mDidAppSwitch = false;
mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
mActivityStartController.schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
}
}
@@ -15491,7 +15434,7 @@ public class ActivityManagerService extends IActivityManager.Stub
private void dumpActivityStarterLocked(PrintWriter pw, String dumpPackage) {
pw.println("ACTIVITY MANAGER STARTER (dumpsys activity starter)");
mActivityStarter.dump(pw, "", dumpPackage);
mActivityStartController.dump(pw, "", dumpPackage);
}
void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
@@ -24248,8 +24191,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
synchronized (ActivityManagerService.this) {
return startActivitiesInPackage(packageUid, packageName, intents, resolvedTypes,
/*resultTo*/ null, bOptions, userId);
return mActivityStartController.startActivitiesInPackage(packageUid, packageName,
intents, resolvedTypes, /*resultTo*/ null, bOptions, userId);
}
}
@@ -24400,7 +24343,7 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println(" Reason: " + reason);
}
pw.println();
mActivityStarter.dump(pw, " ", null);
mActivityStartController.dump(pw, " ", null);
pw.println();
pw.println("-------------------------------------------------------------------------------");
dumpActivitiesLocked(null /* fd */, pw, null /* args */, 0 /* opti */,

View File

@@ -3892,11 +3892,12 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
try {
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
destIntent.getComponent(), 0, srec.userId);
int res = mService.mActivityStarter.startActivityLocked(srec.app.thread,
destIntent, null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null,
null, parent.appToken, null, 0, -1, parent.launchedFromUid,
parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null,
false, true, null, null, "navigateUpTo");
int res = mService.getActivityStartController().startActivity(
srec.app.thread, destIntent, null /*ephemeralIntent*/, null, aInfo,
null /*rInfo*/, null, null, parent.appToken, null, 0, -1,
parent.launchedFromUid, parent.launchedFromPackage, -1,
parent.launchedFromUid, 0, null, false, true, null, null,
"navigateUpTo");
foundParentInTask = res == ActivityManager.START_SUCCESS;
} catch (RemoteException e) {
foundParentInTask = false;

View File

@@ -129,7 +129,7 @@ import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManagerInternal;
import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
@@ -364,6 +364,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
* is being brought in front of us. */
boolean mUserLeaving = false;
/** Set when a power hint has started, but not ended. */
private boolean mPowerHintSent;
/**
* We don't want to allow the device to go to sleep while in the process
* of launching an activity. This is primarily to allow alarm intent
@@ -978,7 +981,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
// Send launch end powerhint when idle
mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded();
sendPowerHintForLaunchEndIfNeeded();
return true;
}
@@ -1470,7 +1473,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// a chance to initialize itself while in the background, making the
// switch back to it faster and look better.
if (isFocusedStack(stack)) {
mService.startSetupActivityLocked();
mService.getActivityStartController().startSetupActivity();
}
// Update any services we are bound to that might care about whether
@@ -1531,6 +1534,32 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
"activity", r.intent.getComponent(), false, false, true);
}
void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) {
boolean sendHint = forceSend;
if (!sendHint) {
// If not forced, send power hint when the activity's process is different than the
// current resumed activity.
final ActivityRecord resumedActivity = getResumedActivityLocked();
sendHint = resumedActivity == null
|| resumedActivity.app == null
|| !resumedActivity.app.equals(targetActivity.app);
}
if (sendHint && mService.mLocalPowerManager != null) {
mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 1);
mPowerHintSent = true;
}
}
void sendPowerHintForLaunchEndIfNeeded() {
// Trigger launch power hint if activity is launched
if (mPowerHintSent && mService.mLocalPowerManager != null) {
mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 0);
mPowerHintSent = false;
}
}
boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, boolean ignoreTargetSecurity, ProcessRecord callerApp,
@@ -2481,14 +2510,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
}
private void deferUpdateBounds(int activityType) {
void deferUpdateBounds(int activityType) {
final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
if (stack != null) {
stack.deferUpdateBounds();
}
}
private void continueUpdateBounds(int activityType) {
void continueUpdateBounds(int activityType) {
final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
if (stack != null) {
stack.continueUpdateBounds();
@@ -3335,7 +3364,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
// Send launch end powerhint before going sleep
mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded();
sendPowerHintForLaunchEndIfNeeded();
removeSleepTimeouts();
@@ -4473,7 +4502,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
*
* @param task The task to put into resizing mode
*/
private void setResizingDuringAnimation(TaskRecord task) {
void setResizingDuringAnimation(TaskRecord task) {
mResizingTasksDuringAnimation.add(task.taskId);
task.setTaskDockedResizing(true);
}
@@ -4532,8 +4561,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
&& task.getRootActivity() != null) {
final ActivityRecord targetActivity = task.getTopActivity();
mService.mActivityStarter.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */,
targetActivity);
sendPowerHintForLaunchStartIfNeeded(true /* forceSend */, targetActivity);
mActivityMetricsLogger.notifyActivityLaunching();
try {
mService.moveTaskToFrontLocked(task.taskId, 0, bOptions,
@@ -4550,8 +4578,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
setResizingDuringAnimation(task);
}
mService.mActivityStarter.postStartActivityProcessing(task.getTopActivity(),
ActivityManager.START_TASK_TO_FRONT, task.getStack());
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
task.getTopActivity(), ActivityManager.START_TASK_TO_FRONT,
task.getStack());
return ActivityManager.START_TASK_TO_FRONT;
}
callingUid = task.mCallingUid;
@@ -4559,8 +4588,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
intent = task.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
userId = task.userId;
int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
null, null, 0, 0, bOptions, userId, task, "startActivityFromRecents");
int result = mService.getActivityStartController().startActivityInPackage(callingUid,
callingPackage, intent, null, null, null, 0, 0, bOptions, userId, task,
"startActivityFromRecents");
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
setResizingDuringAnimation(task);
}

View File

@@ -0,0 +1,434 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.am;
import static android.app.ActivityManager.START_SUCCESS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.ALLOW_FULL_ONLY;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
import android.app.ProfilerInfo;
import android.app.WaitResult;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
import android.os.FactoryTest;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.ActivityStarter.DefaultFactory;
import com.android.server.am.ActivityStarter.Factory;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
/**
* Controller for delegating activity launches.
*
* This class' main objective is to take external activity start requests and prepare them into
* a series of discrete activity launches that can be handled by an {@link ActivityStarter}. It is
* also responsible for handling logic that happens around an activity launch, but doesn't
* necessarily influence the activity start. Examples include power hint management, processing
* through the pending activity list, and recording home activity launches.
*/
public class ActivityStartController {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStartController" : TAG_AM;
private static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 1;
private final ActivityManagerService mService;
private final ActivityStackSupervisor mSupervisor;
private final ActivityStartInterceptor mInterceptor;
/** Last home activity record we attempted to start. */
private ActivityRecord mLastHomeActivityStartRecord;
/** Temporary array to capture start activity results */
private ActivityRecord[] tmpOutRecord = new ActivityRecord[1];
/**The result of the last home activity we attempted to start. */
private int mLastHomeActivityStartResult;
/** A list of activities that are waiting to launch. */
private final ArrayList<ActivityStackSupervisor.PendingActivityLaunch>
mPendingActivityLaunches = new ArrayList<>();
private final Factory mFactory;
private final Handler mHandler;
private final class StartHandler extends Handler {
public StartHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case DO_PENDING_ACTIVITY_LAUNCHES_MSG:
synchronized (mService) {
doPendingActivityLaunches(true);
}
break;
}
}
}
/**
* TODO(b/64750076): Capture information necessary for dump and
* {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object
* around */
private ActivityStarter mLastStarter;
ActivityStartController(ActivityManagerService service) {
this(service, service.mStackSupervisor, new DefaultFactory());
}
@VisibleForTesting
ActivityStartController(ActivityManagerService service, ActivityStackSupervisor supervisor,
Factory factory) {
mService = service;
mSupervisor = supervisor;
mHandler = new StartHandler(mService.mHandlerThread.getLooper());
mInterceptor = new ActivityStartInterceptor(mService, mSupervisor);
mFactory = factory;
}
/**
* Retrieves a starter to be used for a new start request. The starter will be added to the
* active starters list.
*
* TODO(b/64750076): This should be removed when {@link #obtainStarter} is implemented. At that
* time, {@link ActivityStarter#execute} will be able to handle cleaning up the starter's
* internal references.
*/
private ActivityStarter createStarter() {
mLastStarter = mFactory.getStarter(this, mService, mService.mStackSupervisor, mInterceptor);
return mLastStarter;
}
/**
* TODO(b/64750076): Remove once we directly expose starter interface to callers through
* {@link #obtainStarter}.
*/
int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, TaskRecord inTask, String reason) {
return createStarter().startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, outActivity, inTask, reason);
}
/**
* TODO(b/64750076): usage of this doesn't seem right. We're making decisions based off the
* last starter for an arbitrary task record. Re-evaluate whether we can remove.
*/
void postStartActivityProcessingForLastStarter(ActivityRecord r, int result,
ActivityStack targetStack) {
mLastStarter.postStartActivityProcessing(r, result, targetStack);
}
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
mSupervisor.moveHomeStackTaskToTop(reason);
final ActivityStarter starter = createStarter();
mLastHomeActivityStartResult = starter.startActivityLocked(null /*caller*/, intent,
null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/,
null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/,
null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
false /*componentSpecified*/, tmpOutRecord, null /*inTask*/,
"startHomeActivity: " + reason);
mLastHomeActivityStartRecord = tmpOutRecord[0];
if (mSupervisor.inResumeTopActivity) {
// If we are in resume section already, home activity will be initialized, but not
// resumed (to avoid recursive resume) and will stay that way until something pokes it
// again. We need to schedule another resume.
mSupervisor.scheduleResumeTopActivities();
}
}
/**
* Starts the "new version setup screen" if appropriate.
*/
void startSetupActivity() {
// Only do this once per boot.
if (mService.getCheckedForSetup()) {
return;
}
// We will show this screen if the current one is a different
// version than the last one shown, and we are not running in
// low-level factory test mode.
final ContentResolver resolver = mService.mContext.getContentResolver();
if (mService.mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL &&
Settings.Global.getInt(resolver,
Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
mService.setCheckedForSetup(true);
// See if we should be showing the platform update setup UI.
final Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
final List<ResolveInfo> ris = mService.mContext.getPackageManager()
.queryIntentActivities(intent,
PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
if (!ris.isEmpty()) {
final ResolveInfo ri = ris.get(0);
String vers = ri.activityInfo.metaData != null
? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
: null;
if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
vers = ri.activityInfo.applicationInfo.metaData.getString(
Intent.METADATA_SETUP_VERSION);
}
String lastVers = Settings.Secure.getString(
resolver, Settings.Secure.LAST_SETUP_SHOWN);
if (vers != null && !vers.equals(lastVers)) {
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name));
startActivity(null, intent, null /*ephemeralIntent*/, null, ri.activityInfo,
null /*rInfo*/, null, null, null, null, 0, 0, 0, null, 0, 0, 0, null,
false, false, null, null, "startSetupActivity");
}
}
}
}
final int startActivityInPackage(int uid, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, Bundle bOptions, int userId,
TaskRecord inTask, String reason) {
userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivityInPackage",
null);
// TODO: Switch to user app stacks here.
return startActivityMayWait(null, uid, callingPackage,
intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
null, null, null, bOptions, false, userId, inTask, reason);
}
final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId) {
final String reason = "startActivityInPackage";
userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, reason, null);
// TODO: Switch to user app stacks here.
int ret = startActivities(null, uid, callingPackage, intents, resolvedTypes, resultTo,
bOptions, userId, reason);
return ret;
}
/**
* TODO(b/64750076): Remove once we directly expose starter interface to callers through
* {@link #obtainStarter}.
*/
int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, WaitResult outResult,
Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
TaskRecord inTask, String reason) {
return createStarter().startActivityMayWait(caller, callingUid, callingPackage, intent,
resolvedType, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
startFlags, profilerInfo, outResult, globalConfig, bOptions,
ignoreTargetSecurity,
userId, inTask, reason);
}
int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId,
String reason) {
if (intents == null) {
throw new NullPointerException("intents is null");
}
if (resolvedTypes == null) {
throw new NullPointerException("resolvedTypes is null");
}
if (intents.length != resolvedTypes.length) {
throw new IllegalArgumentException("intents are length different than resolvedTypes");
}
final int realCallingPid = Binder.getCallingPid();
final int realCallingUid = Binder.getCallingUid();
int callingPid;
if (callingUid >= 0) {
callingPid = -1;
} else if (caller == null) {
callingPid = realCallingPid;
callingUid = realCallingUid;
} else {
callingPid = callingUid = -1;
}
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mService) {
ActivityRecord[] outActivity = new ActivityRecord[1];
for (int i=0; i < intents.length; i++) {
Intent intent = intents[i];
if (intent == null) {
continue;
}
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
boolean componentSpecified = intent.getComponent() != null;
// Don't modify the client's object!
intent = new Intent(intent);
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
null, userId);
// TODO: New, check if this is correct
aInfo = mService.getActivityInfoForUser(aInfo, userId);
if (aInfo != null &&
(aInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
throw new IllegalArgumentException(
"FLAG_CANT_SAVE_STATE not supported here");
}
ActivityOptions options = ActivityOptions.fromBundle(
i == intents.length - 1 ? bOptions : null);
int res = startActivity(caller, intent, null /*ephemeralIntent*/,
resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, 0,
options, false, componentSpecified, outActivity, null, reason);
if (res < 0) {
return res;
}
resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
return START_SUCCESS;
}
void schedulePendingActivityLaunches(long delayMs) {
mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
mHandler.sendMessageDelayed(msg, delayMs);
}
void doPendingActivityLaunches(boolean doResume) {
while (!mPendingActivityLaunches.isEmpty()) {
final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
final ActivityStarter starter = createStarter();
try {
starter.startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume,
null, null, null /*outRecords*/);
} catch (Exception e) {
Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
pal.sendErrorResult(e.getMessage());
}
}
}
void addPendingActivityLaunch(PendingActivityLaunch launch) {
mPendingActivityLaunches.add(launch);
}
boolean clearPendingActivityLaunches(String packageName) {
final int pendingLaunches = mPendingActivityLaunches.size();
for (int palNdx = pendingLaunches - 1; palNdx >= 0; --palNdx) {
final PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
final ActivityRecord r = pal.r;
if (r != null && r.packageName.equals(packageName)) {
mPendingActivityLaunches.remove(palNdx);
}
}
return mPendingActivityLaunches.size() < pendingLaunches;
}
void dump(PrintWriter pw, String prefix, String dumpPackage) {
pw.print(prefix);
pw.print("mLastHomeActivityStartResult=");
pw.println(mLastHomeActivityStartResult);
if (mLastHomeActivityStartRecord != null) {
pw.print(prefix);
pw.println("mLastHomeActivityStartRecord:");
mLastHomeActivityStartRecord.dump(pw, prefix + " ");
}
final boolean dumpPackagePresent = dumpPackage != null;
if (mLastStarter != null) {
final boolean dump = !dumpPackagePresent
|| mLastStarter.relatedToPackage(dumpPackage)
|| (mLastHomeActivityStartRecord != null
&& dumpPackage.equals(mLastHomeActivityStartRecord.packageName));
if (dump) {
pw.print(prefix);
mLastStarter.dump(pw, prefix + " ");
if (dumpPackagePresent) {
return;
}
}
}
if (dumpPackagePresent) {
pw.print(prefix);
pw.println("(nothing)");
}
}
}

View File

@@ -33,7 +33,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
@@ -45,7 +44,6 @@ import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
@@ -55,7 +53,6 @@ import static android.view.Display.INVALID_DISPLAY;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
@@ -77,9 +74,9 @@ import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IApplicationThread;
import android.app.PendingIntent;
import android.app.ProfilerInfo;
@@ -96,7 +93,6 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -109,6 +105,7 @@ import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
@@ -116,11 +113,10 @@ import com.android.server.pm.InstantAppResolver;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
/**
* Controller for interpreting how and then launching activities.
* Controller for interpreting how and then launching an activity.
*
* This class collects all the logic for determining how an intent and flags should be turned into
* an activity and associated task and stack.
@@ -137,7 +133,7 @@ class ActivityStarter {
private final ActivityStackSupervisor mSupervisor;
private final ActivityStartInterceptor mInterceptor;
final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
private final ActivityStartController mController;
// Share state variable among methods when starting an activity.
private ActivityRecord mStartActivity;
@@ -171,7 +167,6 @@ class ActivityStarter {
private boolean mNoAnimation;
private boolean mKeepCurTransition;
private boolean mAvoidMoveToFront;
private boolean mPowerHintSent;
// We must track when we deliver the new intent since multiple code paths invoke
// {@link #deliverNewIntent}. This is due to early returns in the code path. This flag is used
@@ -182,10 +177,6 @@ class ActivityStarter {
private IVoiceInteractionSession mVoiceSession;
private IVoiceInteractor mVoiceInteractor;
// Last home activity record we attempted to start
private final ActivityRecord[] mLastHomeActivityStartRecord = new ActivityRecord[1];
// The result of the last home activity we attempted to start.
private int mLastHomeActivityStartResult;
// Last activity record we attempted to start
private final ActivityRecord[] mLastStartActivityRecord = new ActivityRecord[1];
// The result of the last activity we attempted to start.
@@ -195,48 +186,49 @@ class ActivityStarter {
// The reason we were trying to start the last activity
private String mLastStartReason;
private void reset() {
mStartActivity = null;
mIntent = null;
mCallingUid = -1;
mOptions = null;
mLaunchTaskBehind = false;
mLaunchFlags = 0;
mLaunchMode = INVALID_LAUNCH_MODE;
mLaunchBounds.setEmpty();
mNotTop = null;
mDoResume = false;
mStartFlags = 0;
mSourceRecord = null;
mPreferredDisplayId = INVALID_DISPLAY;
mInTask = null;
mAddingToTask = false;
mReuseTask = null;
mNewTaskInfo = null;
mNewTaskIntent = null;
mSourceStack = null;
mTargetStack = null;
mMovedToFront = false;
mNoAnimation = false;
mKeepCurTransition = false;
mAvoidMoveToFront = false;
mVoiceSession = null;
mVoiceInteractor = null;
mIntentDelivered = false;
/**
* An interface that to provide {@link ActivityStarter} instances to the controller. This is
* used by tests to inject their own starter implementations for verification purposes.
*/
@VisibleForTesting
interface Factory {
/**
* Generates an {@link ActivityStarter} that is ready to handle a new start request.
* @param controller The {@link ActivityStartController} which the starter who will own
* this instance.
* @return an {@link ActivityStarter}
*/
ActivityStarter getStarter(ActivityStartController controller,
ActivityManagerService service, ActivityStackSupervisor supervisor,
ActivityStartInterceptor interceptor);
}
ActivityStarter(ActivityManagerService service) {
/**
* Default implementation of {@link StarterFactory}.
*/
static class DefaultFactory implements Factory {
@Override
public ActivityStarter getStarter(ActivityStartController controller,
ActivityManagerService service, ActivityStackSupervisor supervisor,
ActivityStartInterceptor interceptor) {
// TODO(b/64750076): Investigate recycling instances to reduce object creation overhead.
return new ActivityStarter(controller, service, supervisor, interceptor);
}
}
ActivityStarter(ActivityStartController controller, ActivityManagerService service,
ActivityStackSupervisor supervisor, ActivityStartInterceptor interceptor) {
mController = controller;
mService = service;
mSupervisor = mService.mStackSupervisor;
mInterceptor = new ActivityStartInterceptor(mService, mSupervisor);
mSupervisor = supervisor;
mInterceptor = interceptor;
}
boolean relatedToPackage(String packageName) {
return (mLastStartActivityRecord[0] != null
&& packageName.equals(mLastStartActivityRecord[0].packageName))
|| (mStartActivity != null
&& packageName.equals(mStartActivity.packageName));
}
int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
@@ -268,7 +260,7 @@ class ActivityStarter {
return getExternalResult(mLastStartActivityResult);
}
public static int getExternalResult(int result) {
static int getExternalResult(int result) {
// Aborted results are treated as successes externally, but we must track them internally.
return result != START_ABORTED ? result : START_SUCCESS;
}
@@ -536,9 +528,8 @@ class ActivityStarter {
|| stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
PendingActivityLaunch pal = new PendingActivityLaunch(r,
sourceRecord, startFlags, stack, callerApp);
mPendingActivityLaunches.add(pal);
mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
sourceRecord, startFlags, stack, callerApp));
ActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
}
@@ -555,7 +546,7 @@ class ActivityStarter {
mService.mDidAppSwitch = true;
}
doPendingActivityLaunchesLocked(false);
mController.doPendingActivityLaunches(false);
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
options, inTask, outActivity);
@@ -582,7 +573,6 @@ class ActivityStarter {
}
void postStartActivityProcessing(ActivityRecord r, int result, ActivityStack targetStack) {
if (ActivityManager.isStartResultFatalError(result)) {
return;
}
@@ -620,34 +610,6 @@ class ActivityStarter {
}
}
void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
mSupervisor.moveHomeStackTaskToTop(reason);
mLastHomeActivityStartResult = startActivityLocked(null /*caller*/, intent,
null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/,
null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/,
null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
false /*componentSpecified*/, mLastHomeActivityStartRecord /*outActivity*/,
null /*inTask*/, "startHomeActivity: " + reason);
if (mSupervisor.inResumeTopActivity) {
// If we are in resume section already, home activity will be initialized, but not
// resumed (to avoid recursive resume) and will stay that way until something pokes it
// again. We need to schedule another resume.
mSupervisor.scheduleResumeTopActivities();
}
}
void startConfirmCredentialIntent(Intent intent, Bundle optionsBundle) {
intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
FLAG_ACTIVITY_TASK_ON_HOME);
ActivityOptions options = (optionsBundle != null ? new ActivityOptions(optionsBundle)
: ActivityOptions.makeBasic());
options.setLaunchTaskId(mSupervisor.getHomeActivity().getTask().taskId);
mService.mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
}
final int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
@@ -858,112 +820,7 @@ class ActivityStarter {
}
}
final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo,
Bundle bOptions, int userId, String reason) {
if (intents == null) {
throw new NullPointerException("intents is null");
}
if (resolvedTypes == null) {
throw new NullPointerException("resolvedTypes is null");
}
if (intents.length != resolvedTypes.length) {
throw new IllegalArgumentException("intents are length different than resolvedTypes");
}
final int realCallingPid = Binder.getCallingPid();
final int realCallingUid = Binder.getCallingUid();
int callingPid;
if (callingUid >= 0) {
callingPid = -1;
} else if (caller == null) {
callingPid = realCallingPid;
callingUid = realCallingUid;
} else {
callingPid = callingUid = -1;
}
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mService) {
ActivityRecord[] outActivity = new ActivityRecord[1];
for (int i=0; i<intents.length; i++) {
Intent intent = intents[i];
if (intent == null) {
continue;
}
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
boolean componentSpecified = intent.getComponent() != null;
// Don't modify the client's object!
intent = new Intent(intent);
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
null, userId);
// TODO: New, check if this is correct
aInfo = mService.getActivityInfoForUser(aInfo, userId);
if (aInfo != null &&
(aInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
throw new IllegalArgumentException(
"FLAG_CANT_SAVE_STATE not supported here");
}
ActivityOptions options = ActivityOptions.fromBundle(
i == intents.length - 1 ? bOptions : null);
int res = startActivityLocked(caller, intent, null /*ephemeralIntent*/,
resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, 0,
options, false, componentSpecified, outActivity, null, reason);
if (res < 0) {
return res;
}
resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
return START_SUCCESS;
}
void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) {
boolean sendHint = forceSend;
if (!sendHint) {
// If not forced, send power hint when the activity's process is different than the
// current resumed activity.
final ActivityRecord resumedActivity = mSupervisor.getResumedActivityLocked();
sendHint = resumedActivity == null
|| resumedActivity.app == null
|| !resumedActivity.app.equals(targetActivity.app);
}
if (sendHint && mService.mLocalPowerManager != null) {
mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 1);
mPowerHintSent = true;
}
}
void sendPowerHintForLaunchEndIfNeeded() {
// Trigger launch power hint if activity is launched
if (mPowerHintSent && mService.mLocalPowerManager != null) {
mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 0);
mPowerHintSent = false;
}
}
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
@@ -1064,7 +921,7 @@ class ActivityStarter {
}
}
sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
@@ -1179,7 +1036,7 @@ class ActivityStarter {
EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
mTargetStack.mLastPausedActivity = null;
sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);
mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
@@ -1225,8 +1082,6 @@ class ActivityStarter {
private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
boolean doResume, int startFlags, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
reset();
mStartActivity = r;
mIntent = r.intent;
mOptions = options;
@@ -1933,6 +1788,7 @@ class ActivityStarter {
return START_SUCCESS;
}
@VisibleForTesting
void updateBounds(TaskRecord task, Rect bounds) {
if (bounds.isEmpty()) {
return;
@@ -1996,20 +1852,6 @@ class ActivityStarter {
return launchFlags;
}
final void doPendingActivityLaunchesLocked(boolean doResume) {
while (!mPendingActivityLaunches.isEmpty()) {
final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
try {
startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null,
null, null /*outRecords*/);
} catch (Exception e) {
Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
pal.sendErrorResult(e.getMessage());
}
}
}
private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, int launchFlags,
ActivityOptions aOptions) {
final TaskRecord task = r.getTask();
@@ -2166,35 +2008,8 @@ class ActivityStarter {
(flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;
}
boolean clearPendingActivityLaunchesLocked(String packageName) {
boolean didSomething = false;
for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
ActivityRecord r = pal.r;
if (r != null && r.packageName.equals(packageName)) {
mPendingActivityLaunches.remove(palNdx);
didSomething = true;
}
}
return didSomething;
}
void dump(PrintWriter pw, String prefix, String dumpPackage) {
void dump(PrintWriter pw, String prefix) {
prefix = prefix + " ";
if (dumpPackage != null) {
if ((mLastStartActivityRecord[0] == null ||
!dumpPackage.equals(mLastHomeActivityStartRecord[0].packageName)) &&
(mLastHomeActivityStartRecord[0] == null ||
!dumpPackage.equals(mLastHomeActivityStartRecord[0].packageName)) &&
(mStartActivity == null || !dumpPackage.equals(mStartActivity.packageName))) {
pw.print(prefix);
pw.println("(nothing)");
return;
}
}
pw.print(prefix);
pw.print("mCurrentUser=");
pw.println(mSupervisor.mCurrentUser);
@@ -2213,15 +2028,6 @@ class ActivityStarter {
pw.println("mLastStartActivityRecord:");
r.dump(pw, prefix + " ");
}
pw.print(prefix);
pw.print("mLastHomeActivityStartResult=");
pw.println(mLastHomeActivityStartResult);
r = mLastHomeActivityStartRecord[0];
if (r != null) {
pw.print(prefix);
pw.println("mLastHomeActivityStartRecord:");
r.dump(pw, prefix + " ");
}
if (mStartActivity != null) {
pw.print(prefix);
pw.println("mStartActivity:");

View File

@@ -407,10 +407,10 @@ class AppErrors {
// recents entry. Let's see if we have a safe-to-restart intent.
final Set<String> cats = task.intent.getCategories();
if (cats != null && cats.contains(Intent.CATEGORY_LAUNCHER)) {
mService.startActivityInPackage(task.mCallingUid,
task.mCallingPackage, task.intent, null, null, null, 0, 0,
ActivityOptions.makeBasic().toBundle(), task.userId, null,
"AppErrors");
mService.getActivityStartController().startActivityInPackage(
task.mCallingUid, task.mCallingPackage, task.intent, null, null,
null, 0, 0, ActivityOptions.makeBasic().toBundle(), task.userId,
null, "AppErrors");
}
}
}

View File

@@ -122,8 +122,8 @@ class AppTaskImpl extends IAppTask.Stub {
throw new IllegalArgumentException("Bad app thread " + appThread);
}
}
return mService.mActivityStarter.startActivityMayWait(appThread, -1, callingPackage,
intent, resolvedType, null, null, null, null, 0, 0, null, null,
return mService.getActivityStartController().startActivityMayWait(appThread, -1,
callingPackage, intent, resolvedType, null, null, null, null, 0, 0, null, null,
null, bOptions, false, callingUser, tr, "AppTaskImpl");
}

View File

@@ -332,12 +332,14 @@ final class PendingIntentRecord extends IIntentSender.Stub {
}
allIntents[allIntents.length-1] = finalIntent;
allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
owner.startActivitiesInPackage(uid, key.packageName, allIntents,
allResolvedTypes, resultTo, options, userId);
owner.getActivityStartController().startActivitiesInPackage(uid,
key.packageName, allIntents, allResolvedTypes, resultTo,
options, userId);
} else {
owner.startActivityInPackage(uid, key.packageName, finalIntent,
resolvedType, resultTo, resultWho, requestCode, 0,
options, userId, null, "PendingIntentRecord");
owner.getActivityStartController().startActivityInPackage(uid,
key.packageName, finalIntent, resolvedType, resultTo,
resultWho, requestCode, 0, options, userId, null,
"PendingIntentRecord");
}
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startActivity intent", e);

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.am;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.service.voice.IVoiceInteractionSession;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
import com.android.server.am.ActivityStarter.Factory;
import org.junit.runner.RunWith;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.times;
import java.util.Random;
/**
* Tests for the {@link ActivityStartController} class.
*
* Build/Install/Run:
* atest FrameworksServicesTests:ActivityStartControllerTests
*/
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStartControllerTests extends ActivityTestsBase {
private ActivityManagerService mService;
private ActivityStartController mController;
private Factory mFactory;
private ActivityStarter mStarter;
@Override
public void setUp() throws Exception {
super.setUp();
mService = createActivityManagerService();
mFactory = mock(Factory.class);
mStarter = mock(ActivityStarter.class);
doReturn(mStarter).when(mFactory).getStarter(any(), any(), any(), any());
mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
}
/**
* Ensures that the starter is correctly invoked on
* {@link ActivityStartController#startActivity}
*/
@Test
@Presubmit
public void testStartActivity() {
final Random random = new Random();
final IApplicationThread applicationThread = mock(IApplicationThread.class);
final Intent intent = mock(Intent.class);
final Intent ephemeralIntent = mock(Intent.class);
final String resolvedType = "TestType";
final ActivityInfo aInfo = mock(ActivityInfo.class);
final ResolveInfo rInfo = mock(ResolveInfo.class);
final IVoiceInteractionSession voiceInteractionSession =
mock(IVoiceInteractionSession.class);
final IVoiceInteractor voiceInteractor = mock(IVoiceInteractor.class);
final IBinder resultTo = mock(IBinder.class);
final String resultWho = "resultWho";
final int requestCode = random.nextInt();
final int callingPid = random.nextInt();
final int callingUid = random.nextInt();
final String callingPackage = "callingPackage";
final int realCallingPid = random.nextInt();
final int realCallingUid = random.nextInt();
final int startFlags = random.nextInt();
final ActivityOptions options = mock(ActivityOptions.class);
final boolean ignoreTargetSecurity = random.nextBoolean();
final boolean componentSpecified = random.nextBoolean();
final ActivityRecord[] outActivity = new ActivityRecord[1];
final TaskRecord inTask = mock(TaskRecord.class);
final String reason ="reason";
mController.startActivity(applicationThread, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceInteractionSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid,
startFlags, options, ignoreTargetSecurity, componentSpecified, outActivity, inTask,
reason);
// The starter should receive a start command with the originally provided parameters
verify(mStarter, times(1)).startActivityLocked(eq(applicationThread), eq(intent),
eq(ephemeralIntent), eq(resolvedType), eq(aInfo), eq(rInfo),
eq(voiceInteractionSession), eq(voiceInteractor), eq(resultTo), eq(resultWho),
eq(requestCode), eq(callingPid), eq(callingUid), eq(callingPackage),
eq(realCallingPid), eq(realCallingUid), eq(startFlags), eq(options),
eq(ignoreTargetSecurity), eq(componentSpecified), eq(outActivity), eq(inTask),
eq(reason));
}
/**
* Ensures that pending launches are processed.
*/
@Test
@Presubmit
public void testPendingActivityLaunches() {
final Random random = new Random();
final ActivityRecord activity = new ActivityBuilder(mService).build();
final ActivityRecord source = new ActivityBuilder(mService).build();
final int startFlags = random.nextInt();
final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ProcessRecord process= new ProcessRecord(null, mService.mContext.getApplicationInfo(),
"name", 12345);
mController.addPendingActivityLaunch(
new PendingActivityLaunch(activity, source, startFlags, stack, process));
final boolean resume = random.nextBoolean();
mController.doPendingActivityLaunches(resume);
verify(mStarter, times(1)).startActivity(eq(activity), eq(source), eq(null),
eq(null), eq(startFlags), eq(resume), eq(null), eq(null), eq(null));
}
}

View File

@@ -65,10 +65,10 @@ import static android.app.ActivityManager.START_INTENT_NOT_RESOLVED;
import com.android.internal.os.BatteryStatsImpl;
/**
* Tests for the {@link ActivityStack} class.
* Tests for the {@link ActivityStarter} class.
*
* Build/Install/Run:
* bit FrameworksServicesTests:com.android.server.am.ActivityStarterTests
* atest FrameworksServicesTests:ActivityStarterTests
*/
@SmallTest
@Presubmit
@@ -76,7 +76,7 @@ import com.android.internal.os.BatteryStatsImpl;
public class ActivityStarterTests extends ActivityTestsBase {
private ActivityManagerService mService;
private ActivityStarter mStarter;
private IPackageManager mPackageManager;
private ActivityStartController mController;
private static final int PRECONDITION_NO_CALLER_APP = 1;
private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
@@ -94,7 +94,9 @@ public class ActivityStarterTests extends ActivityTestsBase {
public void setUp() throws Exception {
super.setUp();
mService = createActivityManagerService();
mStarter = new ActivityStarter(mService);
mController = mock(ActivityStartController.class);
mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
mock(ActivityStartInterceptor.class));
}
@Test
@@ -176,8 +178,10 @@ public class ActivityStarterTests extends ActivityTestsBase {
int expectedResult) {
final ActivityManagerService service = createActivityManagerService();
final IPackageManager packageManager = mock(IPackageManager.class);
final ActivityStarter starter = new ActivityStarter(service);
final ActivityStartController controller = mock(ActivityStartController.class);
final ActivityStarter starter = new ActivityStarter(controller, service,
service.mStackSupervisor, mock(ActivityStartInterceptor.class));
final IApplicationThread caller = mock(IApplicationThread.class);
// If no caller app, return {@code null} {@link ProcessRecord}.