AMS & WMS,應該是app端打交道最多的2個framwork層的service。
ActivityManagerService 是android提供給用於管理Activity運行狀態的系統進程。
本系列共分3個部分,概述,ActivityStatck & Activiy Task.
AMS 主要用於管理Activity之間的交互問題。
核心問題有以下幾個:
1.activity 生命周期管理
2.intent是怎么傳遞數據的。(可能跨進程,以及雙向傳遞)
3.launchmode是怎么使用的。(Task的概念)
一. AMS概述
首先AMS 是一個同我們開發的service非常相似的一個service,只不過它的作用是管理activity。
所以AMS是一個進程,並且當開機以后,它就常駐在系統里面,歸ServiceManager調度。
而AMS啟動后,它開始有一個線程監聽處理客戶的需求。
一下為android5.0 的代碼:
\frameworks\base\services\java\com\android\server\SystemServera.java

private void startBootstrapServices() { // Wait for installd to finish starting up so that it has a chance to // create critical directories such as /data/user with the appropriate // permissions. We need this to complete before we initialize other services. mInstaller = mSystemServiceManager.startService(Installer.class); // Activity manager runs the show. mActivityManagerService = mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService(); mActivityManagerService.setSystemServiceManager(mSystemServiceManager); // Power manager needs to be started early because other services need it. // Native daemons may be watching for it to be registered so it must be ready // to handle incoming binder calls immediately (including being able to verify // the permissions for those calls). mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class); // Now that the power manager has been started, let the activity manager // initialize power management features. mActivityManagerService.initPowerManagement(); // Display manager is needed to provide display metrics before package manager // starts up. mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class); // We need the default display before we can initialize the package manager. mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); // Only run "core" apps if we're encrypting the device. String cryptState = SystemProperties.get("vold.decrypt"); if (ENCRYPTING_STATE.equals(cryptState)) { Slog.w(TAG, "Detected encryption in progress - only parsing core apps"); mOnlyCore = true; } else if (ENCRYPTED_STATE.equals(cryptState)) { Slog.w(TAG, "Device encrypted - only parsing core apps"); mOnlyCore = true; } // Start the package manager. Slog.i(TAG, "Package Manager"); mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); mFirstBoot = mPackageManagerService.isFirstBoot(); mPackageManager = mSystemContext.getPackageManager(); Slog.i(TAG, "User Service"); ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance()); // Initialize attribute cache used to cache resources from packages. AttributeCache.init(mSystemContext); // Set up the Application instance for the system process and get started. mActivityManagerService.setSystemProcess(); }
可以看到AMS在這里啟動。而這個函數startBootstrapServices是在run方法中運行。

public ActivityManagerService(Context systemContext) { mContext = systemContext; mFactoryTest = FactoryTest.getMode(); mSystemThread = ActivityThread.currentActivityThread(); Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); mHandlerThread.start(); mHandler = new MainHandler(mHandlerThread.getLooper()); mFgBroadcastQueue = new BroadcastQueue(this, mHandler, "foreground", BROADCAST_FG_TIMEOUT, false); mBgBroadcastQueue = new BroadcastQueue(this, mHandler, "background", BROADCAST_BG_TIMEOUT, true); mBroadcastQueues[0] = mFgBroadcastQueue; mBroadcastQueues[1] = mBgBroadcastQueue; mServices = new ActiveServices(this); mProviderMap = new ProviderMap(this); // TODO: Move creation of battery stats service outside of activity manager service. File dataDir = Environment.getDataDirectory(); File systemDir = new File(dataDir, "system"); systemDir.mkdirs(); mBatteryStatsService = new BatteryStatsService(systemDir, mHandler); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); mOnBattery = DEBUG_POWER ? true : mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(this); mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats")); mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler); mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml")); // User 0 is the first and only user that runs at boot. mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true)); mUserLru.add(Integer.valueOf(0)); updateStartedUserArrayLocked(); GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); mConfiguration.setToDefaults(); mConfiguration.setLocale(Locale.getDefault()); mConfigurationSeq = mConfiguration.seq = 1; mProcessCpuTracker.init(); mCompatModePackages = new CompatModePackages(this, systemDir, mHandler); mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler); mStackSupervisor = new ActivityStackSupervisor(this); mTaskPersister = new TaskPersister(systemDir, mStackSupervisor); mProcessCpuThread = new Thread("CpuTracker") { @Override public void run() { while (true) { try { try { synchronized(this) { final long now = SystemClock.uptimeMillis(); long nextCpuDelay = (mLastCpuTime.get()+MONITOR_CPU_MAX_TIME)-now; long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now; //Slog.i(TAG, "Cpu delay=" + nextCpuDelay // + ", write delay=" + nextWriteDelay); if (nextWriteDelay < nextCpuDelay) { nextCpuDelay = nextWriteDelay; } if (nextCpuDelay > 0) { mProcessCpuMutexFree.set(true); this.wait(nextCpuDelay); } } } catch (InterruptedException e) { } updateCpuStatsNow(); } catch (Exception e) { Slog.e(TAG, "Unexpected exception collecting process stats", e); } } } }; mLockToAppRequest = new LockToAppRequestDialog(mContext, this); Watchdog.getInstance().addMonitor(this); Watchdog.getInstance().addThread(mHandler); }
mStackSupervisor = new ActivityStackSupervisor(this); mTaskPersister = new TaskPersister(systemDir, mStackSupervisor);
這兩句是ActivityStack & ActivityTask設置的地方。
public void setSystemProcess()就比較簡單了,它不僅注冊了自己一個server, 還注冊了其他的server。
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true); ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats); ServiceManager.addService("meminfo", new MemBinder(this)); ServiceManager.addService("gfxinfo", new GraphicsBinder(this)); ServiceManager.addService("dbinfo", new DbBinder(this)); if (MONITOR_CPU_USAGE) { ServiceManager.addService("cpuinfo", new CpuBinder(this)); } ServiceManager.addService("permission", new PermissionController(this));
二.Activit狀態管理---ActivityStack
1.ActivityState
定義了如下狀態:
狀態變化圖。
三:startActivity
startActivity@ActivityManagerService.java
startActivityAsUser@ActivityManagerService.java
startActivityMayWait@ActivityStack.java
startActivityLocked@ActivityStack.java
sartActivityUncheckedLocked@ActivityStack.java
這5個函數先后關系,就是上面的順序。
public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) { return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, options, UserHandle.getCallingUserId()); }
多了一個
UserHandle.getCallingUserId()
調用者的Userid值,通過bind機制獲得的。
@Override public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) { enforceNotIsolatedCaller("startActivity"); userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivity", null); // TODO: Switch to user app stacks here. return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, null, null, options, false, userId, null, null); }
enforceNotIsolatedCaller 的目的是確認當前用戶是否屬於被隔離的對象。
接下來是 startActivityMayWait
startActivityMayWait
ActivityStackSupervisor.startActivityMayWait

final 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 config, Bundle options, boolean ignoreTargetSecurity, int userId, IActivityContainer iContainer, TaskRecord inTask) { // 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 = resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId); ActivityContainer container = (ActivityContainer)iContainer; synchronized (mService) { if (container != null && container.mParentActivity != null && container.mParentActivity.state != RESUMED) { // Cannot start a child activity if the parent is not resumed. return ActivityManager.START_CANCELED; } 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 ActivityStack stack; if (container == null || container.mStack.isOnHomeDisplay()) { stack = mFocusedStack; } else { stack = container.mStack; } stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0; if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = " + stack.mConfigWillChange); final long origId = Binder.clearCallingIdentity(); if (aInfo != null && (aInfo.applicationInfo.privateFlags &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { // This may be a heavy-weight process! Check to see if we already // have another, different heavy-weight process running. if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) { if (mService.mHeavyWeightProcess != null && (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid || !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) { int appCallingUid = callingUid; if (caller != null) { ProcessRecord callerApp = mService.getRecordForAppLocked(caller); if (callerApp != null) { appCallingUid = callerApp.info.uid; } else { Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid + ") when starting: " + intent.toString()); ActivityOptions.abort(options); return ActivityManager.START_PERMISSION_DENIED; } } IIntentSender target = mService.getIntentSenderLocked( ActivityManager.INTENT_SENDER_ACTIVITY, "android", appCallingUid, userId, null, null, 0, new Intent[] { intent }, new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT, null); Intent newIntent = new Intent(); if (requestCode >= 0) { // Caller is requesting a result. newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true); } newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT, new IntentSender(target)); if (mService.mHeavyWeightProcess.activities.size() > 0) { ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0); newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP, hist.packageName); newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.task.taskId); } newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP, aInfo.packageName); newIntent.setFlags(intent.getFlags()); newIntent.setClassName("android", HeavyWeightSwitcherActivity.class.getName()); intent = newIntent; resolvedType = null; caller = null; callingUid = Binder.getCallingUid(); callingPid = Binder.getCallingPid(); componentSpecified = true; try { ResolveInfo rInfo = AppGlobals.getPackageManager().resolveIntent( intent, null, PackageManager.MATCH_DEFAULT_ONLY | ActivityManagerService.STOCK_PM_FLAGS, userId); aInfo = rInfo != null ? rInfo.activityInfo : null; aInfo = mService.getActivityInfoForUser(aInfo, userId); } catch (RemoteException e) { aInfo = null; } } } } int res = startActivityLocked(caller, intent, resolvedType, aInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, null, container, inTask); Binder.restoreCallingIdentity(origId); if (stack.mConfigWillChange) { // If the caller also wants to switch to a new configuration, // do so now. This allows a clean switch, as we are waiting // for the current activity to pause (so we will not destroy // it), and have not yet started the next activity. mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, "updateConfiguration()"); stack.mConfigWillChange = false; if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Updating to new configuration after starting activity."); mService.updateConfigurationLocked(config, null, false, false); } if (outResult != null) { outResult.result = res; if (res == ActivityManager.START_SUCCESS) { mWaitingActivityLaunched.add(outResult); do { try { mService.wait(); } catch (InterruptedException e) { } } while (!outResult.timeout && outResult.who == null); } else if (res == ActivityManager.START_TASK_TO_FRONT) { ActivityRecord r = stack.topRunningActivityLocked(null); if (r.nowVisible && r.state == RESUMED) { outResult.timeout = false; outResult.who = new ComponentName(r.info.packageName, r.info.name); outResult.totalTime = 0; outResult.thisTime = 0; } else { outResult.thisTime = SystemClock.uptimeMillis(); mWaitingActivityVisible.add(outResult); do { try { mService.wait(); } catch (InterruptedException e) { } } while (!outResult.timeout && outResult.who == null); } } } return res; } }
首先判斷是不是顯示intent,
調用resolveActivity來進行查找。這里有一段注釋:
// Store the found target back into the intent, because now that // we have it we never want to do this again. For example, if the // user navigates back to this point in the history, we should // always restart the exact same activity.
為了確保在history里面的intent統一,只查找一次,獲取ActivityInfo。
判斷當前目標進程是不是重量級進程。
最后調用startActivityLocked來進一部啟動。
如果onResult不為空,還需要將函數的結果寫入這個變量中。在onResult的處理上,有可能會wait,所以這個函數叫startActivityMayWait。
StartActivityLocked
顧名思義,它是線程安全的。

final int startActivityLocked(IApplicationThread caller, Intent intent, String resolvedType, ActivityInfo aInfo, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, Bundle options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container, TaskRecord inTask) { int err = ActivityManager.START_SUCCESS; ProcessRecord callerApp = null; if (caller != null) { callerApp = mService.getRecordForAppLocked(caller); if (callerApp != null) { callingPid = callerApp.pid; callingUid = callerApp.info.uid; } else { Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid + ") when starting: " + intent.toString()); err = ActivityManager.START_PERMISSION_DENIED; } } final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0; if (err == ActivityManager.START_SUCCESS) { Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) + "} from uid " + callingUid + " on display " + (container == null ? (mFocusedStack == null ? Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) : (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY : container.mActivityDisplay.mDisplayId))); } ActivityRecord sourceRecord = null; ActivityRecord resultRecord = null; if (resultTo != null) { sourceRecord = isInAnyStackLocked(resultTo); if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord); if (sourceRecord != null) { if (requestCode >= 0 && !sourceRecord.finishing) { resultRecord = sourceRecord; } } } final int launchFlags = intent.getFlags(); if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) { // Transfer the result target from the source activity to the new // one being started, including any failures. if (requestCode >= 0) { ActivityOptions.abort(options); return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; } resultRecord = sourceRecord.resultTo; if (resultRecord != null && !resultRecord.isInStackLocked()) { resultRecord = null; } resultWho = sourceRecord.resultWho; requestCode = sourceRecord.requestCode; sourceRecord.resultTo = null; if (resultRecord != null) { resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode); } if (sourceRecord.launchedFromUid == callingUid) { // The new activity is being launched from the same uid as the previous // activity in the flow, and asking to forward its result back to the // previous. In this case the activity is serving as a trampoline between // the two, so we also want to update its launchedFromPackage to be the // same as the previous activity. Note that this is safe, since we know // these two packages come from the same uid; the caller could just as // well have supplied that same package name itself. This specifially // deals with the case of an intent picker/chooser being launched in the app // flow to redirect to an activity picked by the user, where we want the final // activity to consider it to have been launched by the previous app activity. callingPackage = sourceRecord.launchedFromPackage; } } if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) { // We couldn't find a class that can handle the given Intent. // That's the end of that! err = ActivityManager.START_INTENT_NOT_RESOLVED; } if (err == ActivityManager.START_SUCCESS && aInfo == null) { // We couldn't find the specific class specified in the Intent. // Also the end of the line. err = ActivityManager.START_CLASS_NOT_FOUND; } if (err == ActivityManager.START_SUCCESS && !isCurrentProfileLocked(userId) && (aInfo.flags & FLAG_SHOW_FOR_ALL_USERS) == 0) { // Trying to launch a background activity that doesn't show for all users. err = ActivityManager.START_NOT_CURRENT_USER_ACTIVITY; } if (err == ActivityManager.START_SUCCESS && sourceRecord != null && sourceRecord.task.voiceSession != null) { // If this activity is being launched as part of a voice session, we need // to ensure that it is safe to do so. If the upcoming activity will also // be part of the voice session, we can only launch it if it has explicitly // said it supports the VOICE category, or it is a part of the calling app. if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) { try { intent.addCategory(Intent.CATEGORY_VOICE); if (!AppGlobals.getPackageManager().activitySupportsIntent( intent.getComponent(), intent, resolvedType)) { Slog.w(TAG, "Activity being started in current voice task does not support voice: " + intent); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } catch (RemoteException e) { Slog.w(TAG, "Failure checking voice capabilities", e); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } } if (err == ActivityManager.START_SUCCESS && voiceSession != null) { // If the caller is starting a new voice session, just make sure the target // is actually allowing it to run this way. try { if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(), intent, resolvedType)) { Slog.w(TAG, "Activity being started in new voice task does not support: " + intent); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } catch (RemoteException e) { Slog.w(TAG, "Failure checking voice capabilities", e); err = ActivityManager.START_NOT_VOICE_COMPATIBLE; } } final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack; if (err != ActivityManager.START_SUCCESS) { if (resultRecord != null) { resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } ActivityOptions.abort(options); return err; } boolean abort = false; final int startAnyPerm = mService.checkPermission( START_ANY_ACTIVITY, callingPid, callingUid); if (startAnyPerm != PERMISSION_GRANTED) { final int componentRestriction = getComponentRestrictionForCallingPackage( aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity); final int actionRestriction = getActionRestrictionForCallingPackage( intent.getAction(), callingPackage, callingPid, callingUid); if (componentRestriction == ACTIVITY_RESTRICTION_PERMISSION || actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) { if (resultRecord != null) { resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } String msg; if (actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) { msg = "Permission Denial: starting " + intent.toString() + " from " + callerApp + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " with revoked permission " + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction()); } else if (!aInfo.exported) { msg = "Permission Denial: starting " + intent.toString() + " from " + callerApp + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " not exported from uid " + aInfo.applicationInfo.uid; } else { msg = "Permission Denial: starting " + intent.toString() + " from " + callerApp + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " requires " + aInfo.permission; } Slog.w(TAG, msg); throw new SecurityException(msg); } if (actionRestriction == ACTIVITY_RESTRICTION_APPOP) { String message = "Appop Denial: starting " + intent.toString() + " from " + callerApp + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " requires " + AppOpsManager.permissionToOp( ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction())); Slog.w(TAG, message); abort = true; } else if (componentRestriction == ACTIVITY_RESTRICTION_APPOP) { String message = "Appop Denial: starting " + intent.toString() + " from " + callerApp + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " requires appop " + AppOpsManager.permissionToOp(aInfo.permission); Slog.w(TAG, message); abort = true; } } abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid, callingPid, resolvedType, aInfo.applicationInfo); if (mService.mController != null) { try { // The Intent we give to the watcher has the extra data // stripped off, since it can contain private information. Intent watchIntent = intent.cloneFilter(); abort |= !mService.mController.activityStarting(watchIntent, aInfo.applicationInfo.packageName); } catch (RemoteException e) { mService.mController = null; } } if (abort) { if (resultRecord != null) { resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } // We pretend to the caller that it was really started, but // they will just get a cancel result. ActivityOptions.abort(options); return ActivityManager.START_SUCCESS; } ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage, intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null, this, container, options); if (outActivity != null) { outActivity[0] = r; } if (r.appTimeTracker == null && sourceRecord != null) { // If the caller didn't specify an explicit time tracker, we want to continue // tracking under any it has. r.appTimeTracker = sourceRecord.appTimeTracker; } final ActivityStack stack = mFocusedStack; if (voiceSession == null && (stack.mResumedActivity == null || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) { if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, realCallingPid, realCallingUid, "Activity start")) { PendingActivityLaunch pal = new PendingActivityLaunch(r, sourceRecord, startFlags, stack); mPendingActivityLaunches.add(pal); ActivityOptions.abort(options); return ActivityManager.START_SWITCHES_CANCELED; } } if (mService.mDidAppSwitch) { // This is the second allowed switch since we stopped switches, // so now just generally allow switches. Use case: user presses // home (switches disabled, switch to home, mDidAppSwitch now true); // user taps a home icon (coming from home so allowed, we hit here // and now allow anyone to switch again). mService.mAppSwitchesAllowedTime = 0; } else { mService.mDidAppSwitch = true; } doPendingActivityLaunchesLocked(false); err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, options, inTask); if (err < 0) { // If someone asked to have the keyguard dismissed on the next // activity start, but we are not actually doing an activity // switch... just dismiss the keyguard now, because we // probably want to see whatever is behind it. notifyActivityDrawnForKeyguard(); } return err; }
@Step1:首先判斷調用者本身的進場是否存在?否則就返回
err = ActivityManager.START_PERMISSION_DENIED;
這種情況是存在的:調用者被系統殺死或者異常退出等。
@Step2:
Intent.FLAG_ACTIVITY_FORWARD_RESULT
考慮這個傳遞標志,如果Activity1 啟動了Actvitiy2,然后Activity2 啟動了Activity3,當Activity3 調用SetResult以后,AMS會把Activity3 的result
傳遞給Activity1.
這是怎么做的的呢?
在啟動Activity3的時候,我們把caller改為Activity1.
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) { // Transfer the result target from the source activity to the new // one being started, including any failures. if (requestCode >= 0) { ActivityOptions.abort(options); return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; } resultRecord = sourceRecord.resultTo; if (resultRecord != null && !resultRecord.isInStackLocked()) { resultRecord = null; } resultWho = sourceRecord.resultWho; requestCode = sourceRecord.requestCode; sourceRecord.resultTo = null; if (resultRecord != null) { resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode); } if (sourceRecord.launchedFromUid == callingUid) { // The new activity is being launched from the same uid as the previous // activity in the flow, and asking to forward its result back to the // previous. In this case the activity is serving as a trampoline between // the two, so we also want to update its launchedFromPackage to be the // same as the previous activity. Note that this is safe, since we know // these two packages come from the same uid; the caller could just as // well have supplied that same package name itself. This specifially // deals with the case of an intent picker/chooser being launched in the app // flow to redirect to an activity picked by the user, where we want the final // activity to consider it to have been launched by the previous app activity. callingPackage = sourceRecord.launchedFromPackage; } }
因為Activity2 已經把接收result的對象設置為Activity1,所以Activity2 不能startactivityforresult去啟動activity3.
@Step3:
沒有合適的Component或者ActivityInfo為空,代碼直接報錯返回。
@Step4:
檢查權限。
@Step5:
生成ActivityRecord r,用來記錄各項判斷的結果。
做完這些了以后,調用startActivityUncheckedLocked
startActivityUncheckedLocked會調用ActivityStack里面的startActivityLocked
startActivityLocked
先判斷Intent.FLAG_ACTIVITY_NEW_TASK, 並確定為newTask。
然后把newTask = true。傳入startActivityLocked。
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) { // Last activity in task had been removed or ActivityManagerService is reusing task. // Insert or replace. // Might not even be in. insertTaskAtTop(rTask, r); mWindowManager.moveTaskToTop(taskId); }
查找task,並發task move to Top。
如果不是newTask,mTaskHistory里面找到它。
找到以后就干了幾件事:
task.addActivityToTop(r); r.putInHistory(); mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen, (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
把Activity r 放到棧的最上面。
ActivityTask
Task是google專門為Android創造的一個概念。
關於launchmode & taskAffinity 可以看我的一篇博客。是以前對於Task & Intent這塊的一個PPT。Android四大組件之Intent
這里我們分析下,google是怎么來實現這個概念的。
關於task的概念在上面的函數startActivityUncheckedLocked里面有講到:
int launchFlags = intent.getFlags();
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
(launchSingleInstance || launchSingleTask)) {
// We have a conflict between the Intent and the Activity manifest, manifest wins.
Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
"\"singleInstance\" or \"singleTask\"");
launchFlags &=
~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
} else {
switch (r.info.documentLaunchMode) {
case ActivityInfo.DOCUMENT_LAUNCH_NONE:
break;
case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
break;
case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
break;
case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
break;
}
}
這段開始就講到launchmode的。
首先就是,判斷是不是launchSingleTask 或者launchSingleInstance 是的化,就忽略FLAG_ACTIVITY_NEW_DOCUMENT這個屬性。
不是這2個launchmode,就去判斷documentLaunchMode的屬性。
final boolean launchTaskBehind = r.mLaunchTaskBehind && !launchSingleTask && !launchSingleInstance && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0; if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && r.resultTo.task.stack != null) { // For whatever reason this activity is being launched into a new // task... yet the caller has requested a result back. Well, that // is pretty messed up, so instead immediately send back a cancel // and let the new task continue launched as normal without a // dependency on its originator. Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result."); r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); r.resultTo = null; }
判斷activity是不是要重新開一個task,如果是的話,就把result去掉,應為在一個new task里面,必定是創建新的activity,所以也就么有傳遞result的必要。
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) { launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } // If we are actually going to launch in to a new task, there are some cases where // we further want to do multiple task. if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { if (launchTaskBehind || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) { launchFlags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK; } }
這個FLAG_ACTIVITY_MULTIPLE_TASK,是和Intent.FLAG_ACTIVITY_NEW_TASK一起使用,系統總是啟動一個新task來啟動activity
ActivityRecord notTop = (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
if (sourceRecord == null && inTask != null && inTask.stack != null) { final Intent baseIntent = inTask.getBaseIntent(); final ActivityRecord root = inTask.getRootActivity(); if (baseIntent == null) { ActivityOptions.abort(options); throw new IllegalArgumentException("Launching into task without base intent: " + inTask); } // If this task is empty, then we are adding the first activity -- it // determines the root, and must be launching as a NEW_TASK. if (launchSingleInstance || launchSingleTask) { if (!baseIntent.getComponent().equals(r.intent.getComponent())) { ActivityOptions.abort(options); throw new IllegalArgumentException("Trying to launch singleInstance/Task " + r + " into different task " + inTask); } if (root != null) { ActivityOptions.abort(options); throw new IllegalArgumentException("Caller with inTask " + inTask + " has root " + root + " but target is singleInstance/Task"); } } // If task is empty, then adopt the interesting intent launch flags in to the // activity being started. if (root == null) { final int flagsOfInterest = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; launchFlags = (launchFlags&~flagsOfInterest) | (baseIntent.getFlags()&flagsOfInterest); intent.setFlags(launchFlags); inTask.setIntent(r); addingToTask = true; // If the task is not empty and the caller is asking to start it as the root // of a new task, then we don't actually want to start this on the task. We // will bring the task to the front, and possibly give it a new intent. } else if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { addingToTask = false; } else { addingToTask = true; } reuseTask = inTask; } else { inTask = null; } if (inTask == null) { if (sourceRecord == null) { // This activity is not being started from another... in this // case we -always- start a new task. if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) { Slog.w(TAG, "startActivity called from non-Activity context; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent); launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // The original activity who is starting us is running as a single // instance... this new activity it is starting must go on its // own task. launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } else if (launchSingleInstance || launchSingleTask) { // The activity being started is a single instance... it always // gets launched into its own task. launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } }
我們來觀察下singletask的套路:

// If the caller is not coming from another activity, but has given us an // explicit task into which they would like us to launch the new activity, // then let's see about doing that. if (sourceRecord == null && inTask != null && inTask.stack != null) { final Intent baseIntent = inTask.getBaseIntent(); final ActivityRecord root = inTask.getRootActivity(); if (baseIntent == null) { ActivityOptions.abort(options); throw new IllegalArgumentException("Launching into task without base intent: " + inTask); } // If this task is empty, then we are adding the first activity -- it // determines the root, and must be launching as a NEW_TASK. if (launchSingleInstance || launchSingleTask) { if (!baseIntent.getComponent().equals(r.intent.getComponent())) { ActivityOptions.abort(options); throw new IllegalArgumentException("Trying to launch singleInstance/Task " + r + " into different task " + inTask); } if (root != null) { ActivityOptions.abort(options); throw new IllegalArgumentException("Caller with inTask " + inTask + " has root " + root + " but target is singleInstance/Task"); } } // If task is empty, then adopt the interesting intent launch flags in to the // activity being started. if (root == null) { final int flagsOfInterest = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; launchFlags = (launchFlags&~flagsOfInterest) | (baseIntent.getFlags()&flagsOfInterest); intent.setFlags(launchFlags); inTask.setIntent(r); addingToTask = true; // If the task is not empty and the caller is asking to start it as the root // of a new task, then we don't actually want to start this on the task. We // will bring the task to the front, and possibly give it a new intent. } else if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { addingToTask = false; } else { addingToTask = true; } reuseTask = inTask; } else { inTask = null; }
如果task原來就是空的,哪就是添加root activity,所以要設置NEW_TASK這個標志位。
如果task已經存在,並且activity是root,我們不需要重新start newtask,只需要把這個task從新放到front就可以。
下面判斷singletask & singleinstance標志位。如果sourceRecord是正在finishing的activity,我們不能在把它當做啟動的源。
如果是singleinstance被拉到前台,由於它在task里面,“有且只有”它一個activity。找到它,並且movetofront。
然后判斷topactivity,以及singletop launchmode。如果都滿足,就把這個task啟動起來,