說實話,android source code從2.3到4.4變化是蠻多的,尤爲是media部分,雖然總的框架是沒有多大變化,可是找起代碼來看仍是挺麻煩的。在android裏面最受傷的是使用了java,jni,jvm,Nativity c++等等,各類設計模式橫行,固然在學習源碼過程當中也意識了編程語言基礎,數據結構,設計模式的重要性。java
android source code 經典的地方:android
1. 大量使用了各類設計模式如單例模式,裝飾模式,工程工廠模式,適配器模式等等。c++
2. 使用了binder驅動進行了IPC通訊。編程
3. 從新設計了消息處理機制。windows
4. 加入了強弱指針管理。設計模式
5. 設計了activity安全的權限管理。安全
6. 對應用開發者可擴展,開發維護作出突出的貢獻。數據結構
7. 使用了JNI技術。app
8. 優化了電源管理服務。框架
。。。。。等等
固然,也有缺點地方。
1. android啓動慢。
由於使用了jni,jvm緣由須要加載不少類及類庫,和各類服務的啓動。爲了用戶體驗,使用了sureface。
上述啓動完後還要啓動launcher,掃描各個應用信息等等。
2. android 是爲嵌入式產品而開發的。實際上內存使用效果來看不是很理想,容易產生碎片,致使android使用越用越慢。
3. 主題定製少,缺少大型遊戲。
4. app常駐內存致使沒法長時間待機。
好吧,不要抱怨那麼多了,生活已經夠無奈的了。開始分析下吧。
1. 在Android系統中,應用程序是由Activity組成的,所以,應用程序的啓動過程實際上就是應用程序中的默認Activity的啓動過程。即在桌面程序(launcher)啓動時候,掃描各個app信息,在設備屏幕中點擊應用程序圖標的情景就會引起Android應用程序中的默認Activity的啓動,從而把應用程序啓動起來。這種啓動方式的特色是會啓動一個新的進程來加載相應的Activity。
2. 由上可知:默認啓動activity是經過launcher(onClick方法)來啓動的,其實就是解析AndroidManifest.xml中的activity標籤及<intent-filter>標籤。而後經過startActivitySafely方法啓動activity。
1 Launcher.java (e:\baiduyundownload\intel_x86_sysimg_4.4_source_files_20131206\intel_x86_sysimg_4.4_source_files_20131206\packages\apps\launcher2\src\com\android\launcher2) 2 3 public void onClick(View v) { 4 // Make sure that rogue clicks don't get through while allapps is launching, or after the 5 // view has detached (it's possible for this to happen if the view is removed mid touch). 6 if (v.getWindowToken() == null) { 7 return; 8 } 9 10 if (!mWorkspace.isFinishedSwitchingState()) { 11 return; 12 } 13 14 Object tag = v.getTag(); 15 if (tag instanceof ShortcutInfo) { 16 // Open shortcut 17 final Intent intent = ((ShortcutInfo) tag).intent; 18 int[] pos = new int[2]; 19 v.getLocationOnScreen(pos); 20 intent.setSourceBounds(new Rect(pos[0], pos[1], 21 pos[0] + v.getWidth(), pos[1] + v.getHeight())); 22 23 boolean success = startActivitySafely(v, intent, tag); 24 25 if (success && v instanceof BubbleTextView) { 26 mWaitingForResume = (BubbleTextView) v; 27 mWaitingForResume.setStayPressed(true); 28 } 29 } else if (tag instanceof FolderInfo) { 30 if (v instanceof FolderIcon) { 31 FolderIcon fi = (FolderIcon) v; 32 handleFolderClick(fi); 33 } 34 } else if (v == mAllAppsButton) { 35 if (isAllAppsVisible()) { 36 showWorkspace(true); 37 } else { 38 onClickAllAppsButton(v); 39 } 40 } 41 }
boolean startActivitySafely(View v, Intent intent, Object tag) { boolean success = false; try { success = startActivity(v, intent, tag); } catch (ActivityNotFoundException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e); } return success; }
boolean startActivity(View v, Intent intent, Object tag) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { // Only launch using the new animation if the shortcut has not opted out (this is a // private contract between launcher and may be ignored in the future). boolean useLaunchAnimation = (v != null) && !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
//useLaunchAnimation表示是否使用點擊Launcher桌面上的圖標,會先有圖標放大的動畫,而後才進入應用,2.3以前是沒有這個選擇的。 if (useLaunchAnimation) { ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); startActivity(intent, opts.toBundle()); } else { startActivity(intent); } return true; } catch (SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Launcher does not have the permission to launch " + intent + ". Make sure to create a MAIN intent-filter for the corresponding activity " + "or use the exported attribute for this activity. " + "tag="+ tag + " intent=" + intent, e); } return false; }
上面的
startActivity(intent, opts.toBundle());在launcher.java中沒有找到定義,其實是在launcher的基類中定義的,須要轉到activity.java中查找定義。
Activity.java (base\core\java\android\app)
@Override public void startActivity(Intent intent, Bundle options) { if (options != null) {
//第二個參數傳入-1表示不須要這個Actvity結束後的返回結果。 startActivityForResult(intent, -1, options); } else { // Note we want to go through this call for compatibility with // applications that may have overridden the method. startActivityForResult(intent, -1); } }
public void startActivityForResult(Intent intent, int requestCode, Bundle options) { if (mParent == null) {
//這裏的mParent確定爲null,由於是從launcher啓動進來的,確定沒有父activity。
//這裏的mInstrumentation是Activity類的成員變量,它的類型是Intrumentation,定義在frameworks/base/core/java/android/app/Instrumentation.java文件中,它用來監控應用程序和系統的交互。
//這裏的mMainThread也是Activity類的成員變量,它的類型是ActivityThread,它表明的是應用程序的主線程,這裏經過mMainThread.getApplicationThread得到它裏面的ApplicationThread成員變量,它是一個Binder對象,後面咱們會看到,ActivityManagerService會使用它來和ActivityThread來進行進程間通訊。這裏咱們需注意的是,這裏的mMainThread表明的是Launcher應用程序運行的進程。
//這裏的mToken也是Activity類的成員變量,它是一個Binder對象的遠程接口。
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } ....... }
Instrumentation.java (base\core\java\android\app) public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; if (mActivityMonitors != null) { synchronized (mSync) { final int N = mActivityMonitors.size(); for (int i=0; i<N; i++) { final ActivityMonitor am = mActivityMonitors.get(i); if (am.match(who, null, intent)) { am.mHits++; if (am.isBlocking()) { return requestCode >= 0 ? am.getResult() : null; } break; } } } } try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess();
//這裏的ActivityManagerNative.getDefault返回ActivityManagerService的遠程接口,即ActivityManagerProxy接口,跟進去就知道了(IActivityManager)。
//intent.resolveTypeIfNeeded返回這個intent的MIME類型,通常沒有AndroidManifest.xml設置MainActivity的MIME類型,所以,這裏返回null。
int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { } return null; }
ActivityManagerNative.java (base\core\java\android\app) public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
//這裏已經很是接近核心了,1. 構造parcel data包和reply包,將相關要啓動的intent數據打進去,而後經過遠程對象mRemote的transact方法(binder IPC)投遞到服務端( ActivityManagerService)
//從調用能夠知道,這裏的參數resolvedType、grantedUriPermissions和resultWho均爲null;參數caller爲ApplicationThread類型的Binder實體;參數resultTo爲一個Binder實體的遠程接口,咱們先不關注它;參數grantedMode爲0,咱們也先不關注它;參數requestCode爲-1;參數onlyIfNeeded和debug均空false。 Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); data.writeString(callingPackage); intent.writeToParcel(data, 0); data.writeString(resolvedType); data.writeStrongBinder(resultTo); data.writeString(resultWho); data.writeInt(requestCode); data.writeInt(startFlags); data.writeString(profileFile); if (profileFd != null) { data.writeInt(1); profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { data.writeInt(0); } if (options != null) { data.writeInt(1); options.writeToParcel(data, 0); } else { data.writeInt(0); } mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0); reply.readException(); int result = reply.readInt(); reply.recycle(); data.recycle(); return result; }
ActivityManagerService.java (base\services\java\com\android\server\am) @Override public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, Bundle options) { return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId()); } @Override public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) { enforceNotIsolatedCaller("startActivity"); userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, true, "startActivity", null); // TODO: Switch to user app stacks here. return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd, null, null, options, userId); }
ActivityStackSupervisor.java (base\services\java\com\android\server\am) final int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config, Bundle options, int userId) { // 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.收集intent的信息() ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profileFile, profileFd, userId); synchronized (mService) { int callingPid; if (callingUid >= 0) { callingPid = -1; } else if (caller == null) { callingPid = Binder.getCallingPid(); callingUid = Binder.getCallingUid(); } else { callingPid = callingUid = -1; } final ActivityStack stack = getFocusedStack(); stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0; if (DEBUG_CONFIGURATION) Slog.v(TAG, "Starting activity when config will change = " + stack.mConfigWillChange); final long origId = Binder.clearCallingIdentity(); if (aInfo != null && (aInfo.applicationInfo.flags&ApplicationInfo.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 realCallingUid = callingUid; if (caller != null) { ProcessRecord callerApp = mService.getRecordForAppLocked(caller); if (callerApp != null) { realCallingUid = 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", realCallingUid, 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, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, startFlags, options, componentSpecified, null); 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, "Updating to new configuration after starting activity."); mService.updateConfigurationLocked(config, null, false, false); } Binder.restoreCallingIdentity(origId); 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) { 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; } }
final int startActivityLocked(IApplicationThread caller, Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options, boolean componentSpecified, ActivityRecord[] outActivity) { int err = ActivityManager.START_SUCCESS; ProcessRecord callerApp = null; if (caller != null) {
//從傳進來的參數caller獲得調用者的進程信息,並保存在callerApp變量中,這裏就是Launcher應用程序的進程信息了 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; } } if (err == ActivityManager.START_SUCCESS) { final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0; Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)); } ActivityRecord sourceRecord = null; ActivityRecord resultRecord = null; if (resultTo != null) {
//參數resultTo是Launcher這個Activity裏面的一個Binder對象,經過它能夠得到Launcher這個Activity的相關信息,保存在sourceRecord變量中。 sourceRecord = isInAnyStackLocked(resultTo); if (DEBUG_RESULTS) Slog.v( TAG, "Will send result to " + resultTo + " " + sourceRecord); if (sourceRecord != null) { if (requestCode >= 0 && !sourceRecord.finishing) { resultRecord = sourceRecord; } } } ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack; 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; resultWho = sourceRecord.resultWho; requestCode = sourceRecord.requestCode; sourceRecord.resultTo = null; if (resultRecord != null) { resultRecord.removeResultsLocked( sourceRecord, resultWho, requestCode); } } 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) { if (resultRecord != null) { resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } setDismissKeyguard(false); ActivityOptions.abort(options); return err; } final int startAnyPerm = mService.checkPermission( START_ANY_ACTIVITY, callingPid, callingUid); final int componentPerm = mService.checkComponentPermission(aInfo.permission, callingPid, callingUid, aInfo.applicationInfo.uid, aInfo.exported); if (startAnyPerm != PERMISSION_GRANTED && componentPerm != PERMISSION_GRANTED) { if (resultRecord != null) { resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode, Activity.RESULT_CANCELED, null); } setDismissKeyguard(false); String msg; 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); } boolean 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. setDismissKeyguard(false); ActivityOptions.abort(options); return ActivityManager.START_SUCCESS; } //建立即將要啓動的Activity的相關信息,並保存在r變量中 ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage, intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, requestCode, componentSpecified, this); if (outActivity != null) { outActivity[0] = r; } final ActivityStack stack = getFocusedStack(); if (stack.mResumedActivity == null || stack.mResumedActivity.info.applicationInfo.uid != callingUid) { if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) { PendingActivityLaunch pal = new PendingActivityLaunch(r, sourceRecord, startFlags, stack); mService.mPendingActivityLaunches.add(pal); setDismissKeyguard(false); 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; } mService.doPendingActivityLaunchesLocked(false); //接下來建立這個來處理下 err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options); if (allPausedActivitiesComplete()) { // 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. dismissKeyguard(); } return err; }
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { final Intent intent = r.intent; final int callingUid = r.launchedFromUid; // 函數首先得到intent的標誌值,保存在launchFlags變量中。這個intent的標誌值的位Intent.FLAG_ACTIVITY_NO_USER_ACTION沒有置位,所以 ,成員變量mUserLeaving的值爲true。這個intent的標誌值的位Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP也沒有置位,所以,變量notTop的值爲null。
int launchFlags = intent.getFlags(); // We'll invoke onUserLeaving before onPause only if the launching // activity did not explicitly state that this is an automated launch. mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0; if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving); // If the caller has asked not to resume at this point, we make note // of this in the record so that we can skip it when trying to find // the top running activity. if (!doResume) { r.delayedResume = true; } ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null; // If the onlyIfNeeded flag is set, then we can do this if the activity // being launched is the same as the one making the call... or, as // a special case, if we do not know the caller then we count the // current top activity as the caller. if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { ActivityRecord checkedCaller = sourceRecord; if (checkedCaller == null) { checkedCaller = getFocusedStack().topRunningNonDelayedActivityLocked(notTop); } if (!checkedCaller.realActivity.equals(r.realActivity)) { // Caller is not the same as launcher, so always needed. startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED; } } 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) { 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 (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { // The activity being started is a single instance... it always // gets launched into its own task. launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } final ActivityStack sourceStack; if (sourceRecord != null) { if (sourceRecord.finishing) { // If the source is finishing, we can't further count it as our source. This // is because the task it is associated with may now be empty and on its way out, // so we don't want to blindly throw it in to that task. Instead we will take // the NEW_TASK flow and try to find a task for it. if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { Slog.w(TAG, "startActivity called from finishing " + sourceRecord + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent); launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } sourceRecord = null; sourceStack = null; } else { sourceStack = sourceRecord.task.stack; } } else { sourceStack = null; } //傳進來的參數r.resultTo爲null,表示Launcher不須要等這個即將要啓動的MainActivity的執行結果。 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { // 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; } boolean addingToTask = false; boolean movedHome = false; TaskRecord reuseTask = null; ActivityStack targetStack;
//當前有沒有Task能夠用來執行這個Activity。因爲r.launchMode的值不爲ActivityInfo.LAUNCH_SINGLE_INSTANCE,所以,它經過findTaskLocked函數來查找存不存這樣的Task,這裏返回的結果是null,即intentActivity爲null,所以,須要建立一個新的Task來啓動這個Activity。 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // If bring to front is requested, and no result is requested, and // we can find a task that was started with this same // component, then instead of launching bring that one to the front. if (r.resultTo == null) { // See if there is a task to bring to the front. If this is // a SINGLE_INSTANCE activity, there can be one and only one // instance of it in the history, and it is always in its own // unique task, so we do a special search. ActivityRecord intentActivity = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE ? findTaskLocked(r) : findActivityLocked(intent, r.info); if (intentActivity != null) { if (r.task == null) { r.task = intentActivity.task; } targetStack = intentActivity.task.stack; targetStack.mLastPausedActivity = null; if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack + " from " + intentActivity); moveHomeStack(targetStack.isHomeStack()); if (intentActivity.task.intent == null) { // This task was started because of movement of // the activity based on affinity... now that we // are actually launching it, we can assign the // base intent. intentActivity.task.setIntent(intent, r.info); } // If the target task is not in the front, then we need // to bring it to the front... except... well, with // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like // to have the same behavior as if a new instance was // being started, which means not bringing it to the front // if the caller is not itself in the front. final ActivityStack lastStack = getLastStack(); ActivityRecord curTop = lastStack == null? null : lastStack.topRunningNonDelayedActivityLocked(notTop); if (curTop != null && (curTop.task != intentActivity.task || curTop.task != lastStack.topTask())) { r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); if (sourceRecord == null || (sourceStack.topActivity() != null && sourceStack.topActivity().task == sourceRecord.task)) { // We really do want to push this one into the // user's face, right now. movedHome = true; if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) { // Caller wants to appear on home activity. intentActivity.task.mOnTopOfHome = true; } targetStack.moveTaskToFrontLocked(intentActivity.task, r, options); options = null; } } // If the caller has requested that the target task be // reset, then do so. if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r); } if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { // We don't need to start a new activity, and // the client said not to do anything if that // is the case, so this is it! And for paranoia, make // sure we have correctly resumed the top activity. if (doResume) { resumeTopActivitiesLocked(targetStack, null, options); } else { ActivityOptions.abort(options); } if (r.task == null) Slog.v(TAG, "startActivityUncheckedLocked: task left null", new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_RETURN_INTENT_TO_CALLER; } if ((launchFlags & (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) { // The caller has requested to completely replace any // existing task with its new activity. Well that should // not be too hard... reuseTask = intentActivity.task; reuseTask.performClearTaskLocked(); reuseTask.setIntent(r.intent, r.info); } else if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // In this situation we want to remove all activities // from the task up to the one being started. In most // cases this means we are resetting the task to its // initial state. ActivityRecord top = intentActivity.task.performClearTaskLocked(r, launchFlags); if (top != null) { if (top.frontOfTask) { // Activity aliases may mean we use different // intents for the top activity, so make sure // the task now has the identity of the new // intent. top.task.setIntent(r.intent, r.info); } ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task); top.deliverNewIntentLocked(callingUid, r.intent); } else { // A special case: we need to // start the activity because it is not currently // running, and the caller has asked to clear the // current task to have this activity at the top. addingToTask = true; // Now pretend like this activity is being started // by the top of its task, so it is put in the // right place. sourceRecord = intentActivity; } } else if (r.realActivity.equals(intentActivity.task.realActivity)) { // In this case the top activity on the task is the // same as the one being launched, so we take that // as a request to bring the task to the foreground. // If the top activity in the task is the root // activity, deliver this new intent to it if it // desires. if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) && intentActivity.realActivity.equals(r.realActivity)) { ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, intentActivity.task); if (intentActivity.frontOfTask) { intentActivity.task.setIntent(r.intent, r.info); } intentActivity.deliverNewIntentLocked(callingUid, r.intent); } else if (!r.intent.filterEquals(intentActivity.task.intent)) { // In this case we are launching the root activity // of the task, but with a different intent. We // should start a new instance on top. addingToTask = true; sourceRecord = intentActivity; } } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) { // In this case an activity is being launched in to an // existing task, without resetting that task. This // is typically the situation of launching an activity // from a notification or shortcut. We want to place // the new activity on top of the current task. addingToTask = true; sourceRecord = intentActivity; } else if (!intentActivity.task.rootWasReset) { // In this case we are launching in to an existing task // that has not yet been started from its front door. // The current task has been brought to the front. // Ideally, we'd probably like to place this new task // at the bottom of its stack, but that's a little hard // to do with the current organization of the code so // for now we'll just drop it. intentActivity.task.setIntent(r.intent, r.info); } if (!addingToTask && reuseTask == null) { // We didn't do anything... but it was needed (a.k.a., client // don't use that intent!) And for paranoia, make // sure we have correctly resumed the top activity. if (doResume) { targetStack.resumeTopActivityLocked(null, options); } else { ActivityOptions.abort(options); } if (r.task == null) Slog.v(TAG, "startActivityUncheckedLocked: task left null", new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_TASK_TO_FRONT; } } } } //String uri = r.intent.toURI(); //Intent intent2 = new Intent(uri); //Slog.i(TAG, "Given intent: " + r.intent); //Slog.i(TAG, "URI is: " + uri); //Slog.i(TAG, "To intent: " + intent2); if (r.packageName != null) { // If the activity being launched is the same as the one currently // at the top, then we need to check if it should only be launched // once. ActivityStack topStack = getFocusedStack(); ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) { if (top.app != null && top.app.thread != null) { if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task); // For paranoia, make sure we have correctly // resumed the top activity. topStack.mLastPausedActivity = null; if (doResume) { resumeTopActivitiesLocked(); } ActivityOptions.abort(options); if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { // We don't need to start a new activity, and // the client said not to do anything if that // is the case, so this is it! if (r.task == null) Slog.v(TAG, "startActivityUncheckedLocked: task left null", new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_RETURN_INTENT_TO_CALLER; } top.deliverNewIntentLocked(callingUid, r.intent); if (r.task == null) Slog.v(TAG, "startActivityUncheckedLocked: task left null", new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_DELIVERED_TO_TOP; } } } } } else { if (r.resultTo != null) { r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); } ActivityOptions.abort(options); if (r.task == null) Slog.v(TAG, "startActivityUncheckedLocked: task left null", new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_CLASS_NOT_FOUND; } boolean newTask = false; boolean keepCurTransition = false; // Should this be considered a new task? if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { targetStack = adjustStackFocus(r); moveHomeStack(targetStack.isHomeStack()); if (reuseTask == null) {
//當前在堆棧頂端的Activity是否就是即將要啓動的Activity,有些狀況下,若是即將要啓動的Activity就在堆棧的頂端,那麼,就不會從新啓動這個Activity的別一個實例了. 如今爲啓動一個newtask,要在一個新的Task裏面來啓動這個Activity了。 r.setTask(targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true), null, true); if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " + r.task); } else { r.setTask(reuseTask, reuseTask, true); } newTask = true; if (!movedHome) { if ((launchFlags & (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) { // Caller wants to appear on home activity, so before starting // their own activity we will bring home to the front. r.task.mOnTopOfHome = true; } } } else if (sourceRecord != null) { TaskRecord sourceTask = sourceRecord.task; targetStack = sourceTask.stack; moveHomeStack(targetStack.isHomeStack()); if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { // In this case, we are adding the activity to an existing // task, but the caller has asked to clear that task if the // activity is already running. ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags); keepCurTransition = true; if (top != null) { ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task); top.deliverNewIntentLocked(callingUid, r.intent); // For paranoia, make sure we have correctly // resumed the top activity. targetStack.mLastPausedActivity = null; if (doResume) { targetStack.resumeTopActivityLocked(null); } ActivityOptions.abort(options); if (r.task == null) Slog.w(TAG, "startActivityUncheckedLocked: task left null", new RuntimeException("here").fillInStackTrace()); return ActivityManager.START_DELIVERED_TO_TOP; } } else if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) { // In this case, we are launching an activity in our own task // that may already be running somewhere in the history, and // we want to shuffle it to the front of the stack if so. final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r); if (top != null) { final TaskRecord task = top.task; task.moveActivityToFrontLocked(top); ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task); top.updateOptionsLocked(options); top.deliverNewIntentLocked(callingUid, r.intent); targetStack.mLastPausedActivity = null; if (doResume) { targetStack.resumeTopActivityLocked(null); } return ActivityManager.START_DELIVERED_TO_TOP; } } // An existing activity is starting this new activity, so we want // to keep the new one in the same task as the one that is starting // it. r.setTask(sourceTask, sourceRecord.thumbHolder, false); if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in existing task " + r.task + " from source " + sourceRecord); } else { // This not being started from an existing activity, and not part // of a new task... just put it in the top task, though these days // this case should never happen. targetStack = adjustStackFocus(r); moveHomeStack(targetStack.isHomeStack()); ActivityRecord prev = targetStack.topActivity(); r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true), null, true); if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new guessed " + r.task); } mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName, intent, r.getUriPermissionsLocked()); if (newTask) { EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId); } ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task); targetStack.mLastPausedActivity = null; targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options); mService.setFocusedActivityLocked(r); return ActivityManager.START_SUCCESS; }
ActivityStack.java (base\services\java\com\android\server\am) final void startActivityLocked(ActivityRecord r, boolean newTask, boolean doResume, boolean keepCurTransition, Bundle options) { TaskRecord rTask = r.task; final int taskId = rTask.taskId; if (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); mWindowManager.moveTaskToTop(taskId); } TaskRecord task = null; if (!newTask) { // If starting in an existing task, find where that is... boolean startIt = true; for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
//這裏的 mTaskHistory.size()表示當前系統中歷史任務的個數,這裏確定是大於0,由於Launcher已經跑起來了。當 mTaskHistory.size()>0時,而且如今要切換新任務時,要作一些任務切的界面操做 task = mTaskHistory.get(taskNdx); if (task == r.task) { // Here it is! Now, if this is not yet visible to the // user, then just add it without starting; it will // get started when the user navigates back to it. if (!startIt) { if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task " + task, new RuntimeException("here").fillInStackTrace()); 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_ON_LOCK_SCREEN) != 0, r.userId); if (VALIDATE_TOKENS) { validateAppTokensLocked(); } ActivityOptions.abort(options); return; } break; } else if (task.numFullscreen > 0) { startIt = false; } } } // Place a new activity at top of stack, so it is next to interact // with the user. // If we are not placing the new activity frontmost, we do not want // to deliver the onUserLeaving callback to the actual frontmost // activity if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) { mStackSupervisor.mUserLeaving = false; if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() behind front, mUserLeaving=false"); } task = r.task; // Slot the activity into the history stack and proceed if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task, new RuntimeException("here").fillInStackTrace()); task.addActivityToTop(r); r.putInHistory(); r.frontOfTask = newTask; if (!isHomeStack() || numActivities() > 0) { // We want to show the starting preview window if we are // switching to a new task, or the next activity's process is // not currently running. boolean showStartingIcon = newTask; ProcessRecord proc = r.app; if (proc == null) { proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid); } if (proc == null || proc.thread == null) { showStartingIcon = true; } if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: starting " + r); if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) { mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, keepCurTransition); mNoAnimActivities.add(r); } else { mWindowManager.prepareAppTransition(newTask ? AppTransition.TRANSIT_TASK_OPEN : AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition); mNoAnimActivities.remove(r); } r.updateOptionsLocked(options); mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen, (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId); boolean doShow = true; if (newTask) { // Even though this activity is starting fresh, we still need // to reset it to make sure we apply affinities to move any // existing activities from other tasks in to it. // If the caller has requested that the target task be // reset, then do so. if ((r.intent.getFlags() &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { resetTaskIfNeededLocked(r, r); doShow = topRunningNonDelayedActivityLocked(null) == r; } } if (SHOW_APP_STARTING_PREVIEW && doShow) { // Figure out if we are transitioning from another activity that is // "has the same starting icon" as the next one. This allows the // window manager to keep the previous window it had previously // created, if it still had one. ActivityRecord prev = mResumedActivity; if (prev != null) { // We don't want to reuse the previous starting preview if: // (1) The current activity is in a different task. if (prev.task != r.task) { prev = null; } // (2) The current activity is already displayed. else if (prev.nowVisible) { prev = null; } } mWindowManager.setAppStartingWindow( r.appToken, r.packageName, r.theme, mService.compatibilityInfoForPackageLocked( r.info.applicationInfo), r.nonLocalizedLabel, r.labelRes, r.icon, r.logo, r.windowFlags, prev != null ? prev.appToken : null, showStartingIcon); } } else { // If this is the first activity, don't do any fancy animations, // because there is nothing for it to animate on top of. mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen, (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId); ActivityOptions.abort(options); } if (VALIDATE_TOKENS) { validateAppTokensLocked(); } //這裏傳進來的參數doResume爲true,因而調用resumeTopActivityLocked進一步操做。 if (doResume) { mStackSupervisor.resumeTopActivitiesLocked(); } }
ActivityStackSupervisor.java (base\services\java\com\android\server\am) boolean resumeTopActivitiesLocked() { return resumeTopActivitiesLocked(null, null, null); } boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions) { if (targetStack == null) { targetStack = getFocusedStack(); } boolean result = false; for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = mStacks.get(stackNdx); if (isFrontStack(stack)) { if (stack == targetStack) {
//把頂層的activity設置resume狀態。 result = stack.resumeTopActivityLocked(target, targetOptions); } else { stack.resumeTopActivityLocked(null); } } } return result; }
ActivityStack.java (base\services\java\com\android\server\am) final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen(""); // Find the first activity that is not finishing.函數先經過調用topRunningActivityLocked函數得到堆棧頂端的Activity,這裏就是MainActivity了,以前已經設置好的,保存在next變量中。 ActivityRecord next = topRunningActivityLocked(null); // Remember how we'll process this pause/resume situation, and ensure // that the state is reset however we wind up proceeding.
//接下來把mUserLeaving的保存在本地變量userLeaving中,而後從新設置爲false,在前面,mUserLeaving的值爲true,所以,這裏的userLeaving爲true。
final boolean userLeaving = mStackSupervisor.mUserLeaving; mStackSupervisor.mUserLeaving = false; if (next == null) { // There are no more activities! Let's just start up the // Launcher... ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home"); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return mStackSupervisor.resumeHomeActivity(prev); } next.delayedResume = false; // If the top activity is the resumed one, nothing to do.
//這裏的mResumedActivity爲Launcher,由於Launcher是當前正被執行的Activity。
//它首先看要啓動的Activity是否就是當前處理Resumed狀態的Activity,若是是的話,那就什麼都不用作,直接返回就能夠了;不然再看一下系統當前是否休眠狀態,若是是的話,再看看要啓動的Activity是否就是當前處於堆棧頂端的Activity,若是是的話,也是什麼都不用作。 if (mResumedActivity == next && next.state == ActivityState.RESUMED && mStackSupervisor.allResumedActivitiesComplete()) { // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Top activity resumed " + next); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } final TaskRecord nextTask = next.task; final TaskRecord prevTask = prev != null ? prev.task : null; if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) { if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); if (prevTask == nextTask) { ArrayList<ActivityRecord> activities = prevTask.mActivities; final int numActivities = activities.size(); for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { final ActivityRecord r = activities.get(activityNdx); // r is usually the same as next, but what if two activities were launched // before prev finished? if (!r.finishing) { r.frontOfTask = true; break; } } } else if (prevTask != topTask()) { // This task is going away but it was supposed to return to the home task. // Now the task above it has to return to the home task instead. final int taskNdx = mTaskHistory.indexOf(prevTask) + 1; mTaskHistory.get(taskNdx).mOnTopOfHome = true; } else { if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next"); return mStackSupervisor.resumeHomeActivity(prev); } } // If we are sleeping, and there is no resumed activity, and the top // activity is paused, well that is the state we want. if (mService.isSleepingOrShuttingDown() && mLastPausedActivity == next && mStackSupervisor.allPausedActivitiesComplete()) { // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Going to sleep and all paused"); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } // Make sure that the user who owns this activity is started. If not, // we will just leave it as is because someone should be bringing // another user's activities to the top of the stack. if (mService.mStartedUsers.get(next.userId) == null) { Slog.w(TAG, "Skipping resume of top activity " + next + ": user " + next.userId + " is stopped"); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } // The activity may be waiting for stop, but that is no longer // appropriate for it. mStackSupervisor.mStoppingActivities.remove(next); mStackSupervisor.mGoingToSleepActivities.remove(next); next.sleeping = false; mStackSupervisor.mWaitingVisibleActivities.remove(next); next.updateOptionsLocked(options); if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next); // If we are currently pausing an activity, then don't do anything // until that is done. if (!mStackSupervisor.allPausedActivitiesComplete()) { if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG, "resumeTopActivityLocked: Skip resume: some activity pausing."); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } // Okay we are now going to start a switch, to 'next'. We may first // have to pause the current activity, but this is an important point // where we have decided to go to 'next' so keep track of that. // XXX "App Redirected" dialog is getting too many false positives // at this point, so turn off for now. if (false) { if (mLastStartedActivity != null && !mLastStartedActivity.finishing) { long now = SystemClock.uptimeMillis(); final boolean inTime = mLastStartedActivity.startTime != 0 && (mLastStartedActivity.startTime + START_WARN_TIME) >= now; final int lastUid = mLastStartedActivity.info.applicationInfo.uid; final int nextUid = next.info.applicationInfo.uid; if (inTime && lastUid != nextUid && lastUid != next.launchedFromUid && mService.checkPermission( android.Manifest.permission.STOP_APP_SWITCHES, -1, next.launchedFromUid) != PackageManager.PERMISSION_GRANTED) { mService.showLaunchWarningLocked(mLastStartedActivity, next); } else { next.startTime = now; mLastStartedActivity = next; } } else { next.startTime = SystemClock.uptimeMillis(); mLastStartedActivity = next; } } // We need to start pausing the current activity so the top one // can be resumed...
//上面兩個條件(mResumedActivity == next && next.state == ActivityState.RESUMED)都不知足,所以,在繼續往下執行以前,首先要把當處於Resumed狀態的Activity推入Paused狀態,而後才能夠啓動新的Activity。可是在將當前這個Resumed狀態的Activity推入Paused狀態以前,首先要看一下當前是否有Activity正在進入Pausing狀態,若是有的話,當前這個Resumed狀態的Activity就要稍後才能進入Paused狀態了,這樣就保證了全部須要進入Paused狀態的Activity串行處理
這裏沒有處於Pausing狀態的Activity,即mPausingActivity爲null,並且mResumedActivity也不爲null,因而就調用startPausingLocked函數把Launcher推入Paused狀態去了。
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving); if (mResumedActivity != null) { pausing = true;
//同時也是在此調用內,最終調用到應用程序activity的onCreate()函數。 startPausingLocked(userLeaving, false); if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity); } if (pausing) { if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG, "resumeTopActivityLocked: Skip resume: need to start pausing"); // At this point we want to put the upcoming activity's process // at the top of the LRU list, since we know we will be needing it // very soon and it would be a waste to let it get killed if it // happens to be sitting towards the end. if (next.app != null && next.app.thread != null) { // No reason to do full oom adj update here; we'll let that // happen whenever it needs to later. mService.updateLruProcessLocked(next.app, false, true); } if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } // If the most recent activity was noHistory but was only stopped rather // than stopped+finished because the device went to sleep, we need to make // sure to finish it as we're making a new activity topmost. if (mService.mSleeping && mLastNoHistoryActivity != null && !mLastNoHistoryActivity.finishing) { if (DEBUG_STATES) Slog.d(TAG, "no-history finish of " + mLastNoHistoryActivity + " on new resume"); requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED, null, "no-history", false); mLastNoHistoryActivity = null; } if (prev != null && prev != next) { if (!prev.waitingVisible && next != null && !next.nowVisible) { prev.waitingVisible = true; mStackSupervisor.mWaitingVisibleActivities.add(prev); if (DEBUG_SWITCH) Slog.v( TAG, "Resuming top, waiting visible to hide: " + prev); } else { // The next activity is already visible, so hide the previous // activity's windows right now so we can show the new one ASAP. // We only do this if the previous is finishing, which should mean // it is on top of the one being resumed so hiding it quickly // is good. Otherwise, we want to do the normal route of allowing // the resumed activity to be shown so we can decide if the // previous should actually be hidden depending on whether the // new one is found to be full-screen or not. if (prev.finishing) { mWindowManager.setAppVisibility(prev.appToken, false); if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: " + prev + ", waitingVisible=" + (prev != null ? prev.waitingVisible : null) + ", nowVisible=" + next.nowVisible); } else { if (DEBUG_SWITCH) Slog.v(TAG, "Previous already visible but still waiting to hide: " + prev + ", waitingVisible=" + (prev != null ? prev.waitingVisible : null) + ", nowVisible=" + next.nowVisible); } } } // Launching this app's activity, make sure the app is no longer // considered stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( next.packageName, false, next.userId); /* TODO: Verify if correct userid */ } catch (RemoteException e1) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " + next.packageName + ": " + e); } // We are starting up the next activity, so tell the window manager // that the previous one will be hidden soon. This way it can know // to ignore it when computing the desired screen orientation. boolean anim = true; if (prev != null) { if (prev.finishing) { if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare close transition: prev=" + prev); if (mNoAnimActivities.contains(prev)) { anim = false; mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false); } else { mWindowManager.prepareAppTransition(prev.task == next.task ? AppTransition.TRANSIT_ACTIVITY_CLOSE : AppTransition.TRANSIT_TASK_CLOSE, false); } mWindowManager.setAppWillBeHidden(prev.appToken); mWindowManager.setAppVisibility(prev.appToken, false); } else { if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: prev=" + prev); if (mNoAnimActivities.contains(next)) { anim = false; mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false); } else { mWindowManager.prepareAppTransition(prev.task == next.task ? AppTransition.TRANSIT_ACTIVITY_OPEN : AppTransition.TRANSIT_TASK_OPEN, false); } } if (false) { mWindowManager.setAppWillBeHidden(prev.appToken); mWindowManager.setAppVisibility(prev.appToken, false); } } else { if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: no previous"); if (mNoAnimActivities.contains(next)) { anim = false; mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false); } else { mWindowManager.prepareAppTransition(AppTransition.TRANSIT_ACTIVITY_OPEN, false); } } if (anim) { next.applyOptionsLocked(); } else { next.clearOptionsLocked(); } ActivityStack lastStack = mStackSupervisor.getLastStack(); if (next.app != null && next.app.thread != null) { if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next); // This activity is now becoming visible. mWindowManager.setAppVisibility(next.appToken, true); // schedule launch ticks to collect information about slow apps. next.startLaunchTickingLocked(); ActivityRecord lastResumedActivity = lastStack == null ? null :lastStack.mResumedActivity; ActivityState lastState = next.state; mService.updateCpuStats(); if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)"); next.state = ActivityState.RESUMED; mResumedActivity = next; next.task.touchActiveTime(); mService.addRecentTaskLocked(next.task); mService.updateLruProcessLocked(next.app, true, true); updateLRUListLocked(next); // Have the window manager re-evaluate the orientation of // the screen based on the new activity order. boolean notUpdated = true; if (mStackSupervisor.isFrontStack(this)) { Configuration config = mWindowManager.updateOrientationFromAppTokens( mService.mConfiguration, next.mayFreezeScreenLocked(next.app) ? next.appToken : null); if (config != null) { next.frozenBeforeDestroy = true; } notUpdated = !mService.updateConfigurationLocked(config, next, false, false); } if (notUpdated) { // The configuration update wasn't able to keep the existing // instance of the activity, and instead started a new one. // We should be all done, but let's just make sure our activity // is still at the top and schedule another run if something // weird happened. ActivityRecord nextNext = topRunningActivityLocked(null); if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Activity config changed during resume: " + next + ", new next: " + nextNext); if (nextNext != next) { // Do over! mStackSupervisor.scheduleResumeTopActivities(); } if (mStackSupervisor.reportResumedActivityLocked(next)) { mNoAnimActivities.clear(); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return false; } try { // Deliver all pending results. ArrayList<ResultInfo> a = next.results; if (a != null) { final int N = a.size(); if (!next.finishing && N > 0) { if (DEBUG_RESULTS) Slog.v( TAG, "Delivering results to " + next + ": " + a); next.app.thread.scheduleSendResult(next.appToken, a); } } if (next.newIntents != null) { next.app.thread.scheduleNewIntent(next.newIntents, next.appToken); } EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId, System.identityHashCode(next), next.task.taskId, next.shortComponentName); next.sleeping = false; mService.showAskCompatModeDialogLocked(next); next.app.pendingUiClean = true; next.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP); next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState, mService.isNextTransitionForward()); mStackSupervisor.checkReadyForSleepLocked(); if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Resumed " + next); } catch (Exception e) { // Whoops, need to restart this activity! if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to " + lastState + ": " + next); next.state = lastState; if (lastStack != null) { lastStack.mResumedActivity = lastResumedActivity; } Slog.i(TAG, "Restarting because process died: " + next); if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null && mStackSupervisor.isFrontStack(lastStack)) { mWindowManager.setAppStartingWindow( next.appToken, next.packageName, next.theme, mService.compatibilityInfoForPackageLocked(next.info.applicationInfo), next.nonLocalizedLabel, next.labelRes, next.icon, next.logo, next.windowFlags, null, true); } mStackSupervisor.startSpecificActivityLocked(next, true, false); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } // From this point on, if something goes wrong there is no way // to recover the activity. try { next.visible = true; completeResumeLocked(next); } catch (Exception e) { // If any exception gets thrown, toss away this // activity and try the next one. Slog.w(TAG, "Exception thrown during resume of " + next, e); requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null, "resume-exception", true); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } next.stopped = false; } else { // Whoops, need to restart this activity! if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else { if (SHOW_APP_STARTING_PREVIEW) { mWindowManager.setAppStartingWindow( next.appToken, next.packageName, next.theme, mService.compatibilityInfoForPackageLocked( next.info.applicationInfo), next.nonLocalizedLabel, next.labelRes, next.icon, next.logo, next.windowFlags, null, true); } if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next); } if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Restarting " + next); mStackSupervisor.startSpecificActivityLocked(next, true, true); } if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; }