diff options
| author | 2017-12-04 15:29:31 +0000 | |
|---|---|---|
| committer | 2017-12-04 15:29:31 +0000 | |
| commit | efb758420d4385e7064df8740611fbd9fdcdbcac (patch) | |
| tree | b9cf4c8e0eeba5abdef2914e064ff6eafe00c849 | |
| parent | 5826e469e9d03eaa5511d413733edde0a1b99048 (diff) | |
| parent | d3624e10392e20158eb2ec1c1cd8ec5bb0914a47 (diff) | |
Merge "Make ActivityStarter single use."
10 files changed, 768 insertions, 393 deletions
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 43a4aefb89ba..c72cb368db7b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -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 */, diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index bdfd82f440a6..f32112099559 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -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; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 445bf679455e..48c08a5718b9 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -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); } diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java new file mode 100644 index 000000000000..317a68f9b09c --- /dev/null +++ b/services/core/java/com/android/server/am/ActivityStartController.java @@ -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)"); + } + } +} diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 2fc5dda6364e..3bee4228d9fb 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -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; + /** + * 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); + } - mIntentDelivered = false; + /** + * 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(ActivityManagerService service) { + 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:"); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index fe380970c33b..d0bc33af9e08 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -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"); } } } diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/am/AppTaskImpl.java index ab86dbdbd106..e5872c0337cf 100644 --- a/services/core/java/com/android/server/am/AppTaskImpl.java +++ b/services/core/java/com/android/server/am/AppTaskImpl.java @@ -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"); } diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 7930f5340205..c26e7703a1ca 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -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); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java new file mode 100644 index 000000000000..56765101baa9 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java @@ -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)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java index 1cec0d93cabe..471726b2979a 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java @@ -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}. |