Merge "Make ActivityStarter single use."
This commit is contained in:
@@ -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 */,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:");
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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}.
|
||||
|
||||
Reference in New Issue
Block a user