Core Source (Android 9.0)
Source | Path(/packages/apps/Launcher3/) |
---|---|
BaseDraggingActivity.java | src/com/android/launcher3/BaseDraggingActivity.java |
ItemClickHandler.java | src/com/android/launcher3/touch/ItemClickHandler.java |
Launcher.java | src/com/android/launcher3/Launcher.java |
Source | Path(/packages/apps/Launcher3/) |
---|---|
Activity.java | core/java/android/app/Activity.java |
ActivityManager.java | core/java/android/app/ActivityManager.java |
ActivityThread.java | core/java/android/app/ActivityThread.java |
ClientTransaction.java | core/java/android/app/servertransaction/ClientTransaction.java |
ClientTransactionHandler.java | core/java/android/app/ClientTransactionHandler.java |
Instrumentation.java | core/java/android/app/Instrumentation.java |
LaunchActivityItem.java | core/java/android/app/servertransaction/LaunchActivityItem.java |
PauseActivityItem.java | core/java/android/app/servertransaction/PauseActivityItem.java |
Process.java | core/java/android/os/Process.java |
TransactionExecutor.java | core/java/android/app/servertransaction/TransactionExecutor.java |
ActivityManagerService.java | services/core/java/com/android/server/am/ActivityManagerService.java |
ActivityStack.java | services/core/java/com/android/server/am/ActivityStack.java |
ActivityStarter.java | services/core/java/com/android/server/am/ActivityStarter.java |
ActivityStartController.java | services/core/java/com/android/server/am/ActivityStartController.java |
ActivityStackSupervisor.java | services/core/java/com/android/server/am/ActivityStackSupervisor.java |
ClientLifecycleManager.java | services/core/java/com/android/server/am/ClientLifecycleManager.java |
I. Preface
It is our daily behavior to click on the application icon of Launcher interface and run various dazzling and powerful applications. As a system engineer, it is necessary for us to study deeply together. When we click on the APK icon until the main interface of the application is finally displayed, during this period, we start from the source code perspective to the end. What was born and what was the logic of processing?
Personally, this process is very necessary for us to understand deeply. For example, sometimes when we click on the application, we have the phenomenon of "Carton" and "black-and-white screen". Are these problems of the application itself or of the system? When you analyze this kind of problem, if you are not familiar with the start-up process of Activity, it will be hard to analyze, and may not be able to get a thorough analysis of the most fundamental reasons.
Not much nonsense. In order to analyze the source code process more conveniently and carefully, we choose Launcher interface click application as the entry point for analysis (through a specific scenario/operation is the best way to study the source code). Then we go directly to the topic. (Lions, this is also a question many interviewers like to ask.)
Launcher's onPause process
Since we are going to start a new APK in the foreground, the current activity will inevitably be switched to the background, so Launcher's onPause process is the first one involved. Activity's life cycle can be read [Android's Four Components']--Activity's "Life Cycle" One article.
2.1 ItemClickHandler.onClick
When you click on an icon of the application Launcher, the callback interface ItemClickHandler executes the startAppShortcutOrInfoActivity in the onClick() method.
// packages/apps/Launcher3/src/com/android/launcher3/Launcher.java public View createShortcut(ViewGroup parent, ShortcutInfo info) { BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.app_icon, parent, false); favorite.applyFromShortcutInfo(info); favorite.setOnClickListener(ItemClickHandler.INSTANCE); favorite.setOnFocusChangeListener(mFocusHandler); return favorite; } // packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java public class ItemClickHandler { public static final OnClickListener INSTANCE = ItemClickHandler::onClick; private static void onClick(View v) { ... ... if (tag instanceof ShortcutInfo) { onClickAppShortcut(v, (ShortcutInfo) tag, launcher); } else if (tag instanceof FolderInfo) { if (v instanceof FolderIcon) { onClickFolderIcon(v); } } else if (tag instanceof AppInfo) { // Execute the startAppShortcutOrInfoActivity method startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher); } else if (tag instanceof LauncherAppWidgetInfo) { if (v instanceof PendingAppWidgetHostView) { onClickPendingWidget((PendingAppWidgetHostView) v, launcher); } } } ... ... }
2.2 ItemClickHandler.startAppShortcutOrInfoActivity
// packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) { Intent intent; if (item instanceof PromiseAppInfo) { PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item; intent = promiseAppInfo.getMarketIntent(launcher); } else { intent = item.getIntent(); } if (intent == null) { throw new IllegalArgumentException("Input must have a valid intent"); } if (item instanceof ShortcutInfo) { ShortcutInfo si = (ShortcutInfo) item; if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI) && intent.getAction() == Intent.ACTION_VIEW) { intent = new Intent(intent); intent.setPackage(null); } } // Execute the startActivitySafely method launcher.startActivitySafely(v, intent, item); }
2.3 Launcher.startActivitySafely
The code eventually goes to Launcher's startActivitySafely() method.
// packages/apps/Launcher3/src/com/android/launcher3/Launcher.java public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { // Calling the startActivitySafely method of the parent BaseDragging Activity boolean success = super.startActivitySafely(v, intent, item); if (success && v instanceof BubbleTextView) { BubbleTextView btv = (BubbleTextView) v; btv.setStayPressed(true); setOnResumeCallback(btv); } return success; // Represents the Activity success of launching a new application }
2.4 BaseDraggingActivity.startActivitySafely
// packages/apps/Launcher3/src/com/android/launcher3/BaseDraggingActivity.java public boolean startActivitySafely(View v, Intent intent, ItemInfo item) { ... ... // Add a flag to indicate that you want to start the Activity in a new Task intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (v != null) { intent.setSourceBounds(getViewBounds(v)); } try { boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW && (item instanceof ShortcutInfo) && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) && !((ShortcutInfo) item).isPromise(); if (isShortcut) { startShortcutIntentSafely(intent, optsBundle, item); } else if (user == null || user.equals(Process.myUserHandle())) { startActivity(intent, optsBundle); // Call the Activity.startActivity method } else { LauncherAppsCompat.getInstance(this).startActivityForProfile( intent.getComponent(), user, intent.getSourceBounds(), optsBundle); } getUserEventDispatcher().logAppLaunch(v, intent); return true; } catch (ActivityNotFoundException|SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e); } return false; }
2.5 Activity.startActivity
// framework/base/core/java/android/app/Activity.java public void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); // options represent Launcher's animation when she starts Activity } else { startActivityForResult(intent, -1); } }
2.6 Activity.startActivityForResult
// framework/base/core/java/android/app/Activity.java public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { // mParent represents the current state of Launcher Activity if (mParent == null) { // Start Activity for the first time, follow this branch options = transferSpringboardActivityOptions(options); // Execute the mInstrumentation.execStartActivity() method Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); ... ... } else { if (options != null) { // Eventually, the mInstrumentation.execStartActivity() method is called mParent.startActivityFromChild(this, intent, requestCode, options); } else { mParent.startActivityFromChild(this, intent, requestCode); } } }
mMainThread is a member variable of the Activity class. Its type is ActivityThread, which represents the main thread of the application.
// frameworks/base/core/java/android/app/ActivityThread.java public final class ActivityThread extends ClientTransactionHandler { ... ... final ApplicationThread mAppThread = new ApplicationThread(); ... ... private class ApplicationThread extends IApplicationThread.Stub {...} ... ... public ApplicationThread getApplicationThread() { return mAppThread; } ... ... }
mMainThread.getApplicationThread() gets the internal member variable of ApplicationThread, which is a Binder object. What's this object for? We'll talk about it later.
2.7 Instrumentation.execStartActivity
Instrumentation is a practical operation class that starts Activity in Android system. It is used to monitor the interaction between application and system.
// frameworks/base/core/java/android/app/Instrumentation.java public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { ... ... try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); // The services provided by ActivityManagerService can be obtained through the ActivityManager.getService() method int result = ActivityManager.getService().startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } return null; }
We study the ActivityManager.getService() method:
// frameworks/base/core/java/android/app/ActivityManager.java public static IActivityManager getService() { return IActivityManagerSingleton.get(); // Get the IActivityManager singleton } private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() { @Override protected IActivityManager create() { final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); final IActivityManager am = IActivityManager.Stub.asInterface(b); return am; } }; // frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
We found that the Binder communication between Activity Manager Service and Activity Manger takes the form of AIDL.
The ActivityManager.getService().startActivity method actually calls the startActivity() method of the ActivityManagerService.
If you don't know about AIDL, you can check it out [Android's Core Mechanisms']--The ubiquitous "AIDL" One article.
2.8 ActivityManagerService.startActivity
Let's look at the startActivity method of ActivityManagerService:
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java @Override public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) { // Move to the startActivityAsUser method return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, UserHandle.getCallingUserId()); }
2.9 ActivityManagerService.startActivityAsUser
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java // Android P has been added. The process here is totally different from before, but the final method is the same. Follow it carefully. public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) { // Continue tuning the startActivityAsUser method return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId, true /*validateIncomingUser*/); } public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) { enforceNotIsolatedCaller("startActivity"); userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser, Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser"); // Before Android P, the ActivityStartController.startActivityMayWait method was called return mActivityStartController.obtainStarter(intent, "startActivityAsUser") .setCaller(caller) .setCallingPackage(callingPackage) .setResolvedType(resolvedType) .setResultTo(resultTo) .setResultWho(resultWho) .setRequestCode(requestCode) .setStartFlags(startFlags) .setProfilerInfo(profilerInfo) .setActivityOptions(bOptions) .setMayWait(userId) // mRequest.mayWait = true is set, which will be used later. .execute(); }
2.10 ActivityStartController.obtainStarter
// frameworks/base/services/core/java/com/android/server/am/ActivityStartController.java import com.android.server.am.ActivityStarter.Factory; private final Factory mFactory; ActivityStarter obtainStarter(Intent intent, String reason) { // What did get (), setIntent(), and setReason(), respectively, are described below. return mFactory.obtain().setIntent(intent).setReason(reason); }
The factory model is used here. Let's follow the specific process.
2.10.1 DefaultFactory.obtain
// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java interface Factory { void setController(ActivityStartController controller); ActivityStarter obtain(); void recycle(ActivityStarter starter); } // DefaultFactory implements classes static class DefaultFactory implements Factory { ... ... @Override public ActivityStarter obtain() { ActivityStarter starter = mStarterPool.acquire(); // The get () method eventually returns an instance of ActivityStarter if (starter == null) { starter = new ActivityStarter(mController, mService, mSupervisor, mInterceptor); } return starter; } ... ... }
2.10.2 ActivityStarter.setIntent
// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java ActivityStarter setIntent(Intent intent) { mRequest.intent = intent; // Assignment for mRequest return this; }
2.10.3 ActivityStarter.setReason
// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java ActivityStarter setReason(String reason) { mRequest.reason = reason; // Assignment for mRequest return this; }
The mActivityStartController.obtainStarter() method eventually obtains an ActivityStarter object containing all the startup information, then performs various assignment processing, and finally executes the execute method.
2.11 ActivityStarter.execute
// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java // The setMayWait(userId) method is executed above. ActivityStarter setMayWait(int userId) { mRequest.mayWait = true; mRequest.userId = userId; return this; } int execute() { try { if (mRequest.mayWait) { // The setMayWait() method is set to true return startActivityMayWait(mRequest.caller, mRequest.callingUid, mRequest.callingPackage, mRequest.intent, mRequest.resolvedType, mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo, mRequest.resultWho, mRequest.requestCode, mRequest.startFlags, mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId, mRequest.inTask, mRequest.reason, mRequest.allowPendingRemoteAnimationRegistryLookup, mRequest.originatingPendingIntent); } else { return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo, mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo, mRequest.resultWho, mRequest.requestCode, mRequest.callingPid, mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.componentSpecified, mRequest.outActivity, mRequest.inTask, mRequest.reason, mRequest.allowPendingRemoteAnimationRegistryLookup, mRequest.originatingPendingIntent); } } finally { onExecutionComplete(); } }
After a round trip, we finally came to the startActivityMayWait() method!
2.12 Process Summary
2.13 ActivityStarter.startActivityMayWait
// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java private int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage, Intent intent, String resolvedType, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, WaitResult outResult, Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity, int userId, TaskRecord inTask, String reason, boolean allowPendingRemoteAnimationRegistryLookup, PendingIntentRecord originatingPendingIntent) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); } mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(); boolean componentSpecified = intent.getComponent() != null; final int realCallingPid = Binder.getCallingPid(); final int realCallingUid = Binder.getCallingUid(); ... ... // Analyzing Intent's Data ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0 /* matchFlags */, computeResolveFilterUid( callingUid, realCallingUid, mRequest.filterCallingUid)); ... ... // Collect relevant information in intent ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo); synchronized (mService) { ... ... // Data used to record Activity final ActivityRecord[] outRecord = new ActivityRecord[1]; // Start Activity int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent); Binder.restoreCallingIdentity(origId); ... ... mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]); return res; } }
2.14 ActivityStarter.startActivity -01
// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent, String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, TaskRecord inTask, String reason, boolean allowPendingRemoteAnimationRegistryLookup, PendingIntentRecord originatingPendingIntent) { ... ... // Jump startActivity mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord, inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent); ... ... return getExternalResult(mLastStartActivityResult); }
2.15 ActivityStarter.startActivity -02
// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent, String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup, PendingIntentRecord originatingPendingIntent) { ... ... // Jump startActivity return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, outActivity); }
2.16 ActivityStarter.startActivity -03
// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity) { int result = START_CANCELED; try { // Pause layout mService.mWindowManager.deferSurfaceLayout(); // Call the startActivityUnchecked method result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, outActivity); } finally { final ActivityStack stack = mStartActivity.getStack(); if (!ActivityManager.isStartResultSuccessful(result) && stack != null) { stack.finishActivityLocked(mStartActivity, RESULT_CANCELED, null /* intentResultData */, "startActivity", true /* oomAdj */); } // Continue layout mService.mWindowManager.continueSurfaceLayout(); } postStartActivityProcessing(r, result, mTargetStack); return result; }
startActivity() is called three times, and finally the startActivityUnchecked() method is executed, which decides how to start an activity based on the startup flag and Activity startup mode.
2.17 ActivityStarter.startActivityUnchecked
// frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity) { // Initialization of various configurations that start Activity will be reset before reconfiguration, including Activity Record, Intent, etc. setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor); // Calculate the starting FLAG and assign the calculated value to mLaunchFlags computeLaunchingTaskFlags(); computeSourceStack(); // Setting mLaunchFlags to Intent achieves the purpose of setting the activation mode of Activity mIntent.setFlags(mLaunchFlags); // Get whether there are reusable activities ActivityRecord reusedActivity = getReusableIntentActivity(); ... ... // Reusable Activity is not empty if (reusedActivity != null) { ... ... } ... ... mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition, mOptions); if (mDoResume) { final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked(); if (!mTargetStack.isFocusable() || (topTaskActivity != null && topTaskActivity.mTaskOverlay && mStartActivity != topTaskActivity)) { ... ... } else { if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityUnchecked"); } // Call the resumeFocusedStackTopActivityLocked() method mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); } } else if (mStartActivity != null) { mSupervisor.mRecentTasks.add(mStartActivity.getTask()); } ... ... return START_SUCCESS; }
2.18 ActivityStackSupervisor.resumeFocusedStackTopActivityLocked
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { if (!readyToResume()) { return false; } if (targetStack != null && isFocusedStack(targetStack)) { // Call resumeTopActivityUncheckedLocked method return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); } final ActivityRecord r = mFocusedStack.topRunningActivityLocked(); if (r == null || !r.isState(RESUMED)) { mFocusedStack.resumeTopActivityUncheckedLocked(null, null); } else if (r.isState(RESUMED)) { mFocusedStack.executeAppTransition(targetOptions); } return false; }
2.19 ActivityStack.resumeTopActivityUncheckedLocked
// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { if (mStackSupervisor.inResumeTopActivity) { // Don't even start recursing. return false; } boolean result = false; try { // Protect against recursion. mStackSupervisor.inResumeTopActivity = true; result = resumeTopActivityInnerLocked(prev, options); // Key methodologies final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */); if (next == null || !next.canTurnScreenOn()) { checkReadyForSleep(); } } finally { mStackSupervisor.inResumeTopActivity = false; } return result; }
2.20 ActivityStack.resumeTopActivityInnerLocked
// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { if (!mService.mBooting && !mService.mBooted) { // Not ready yet! return false; } ... ... boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false); if (mResumedActivity != null) { if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Pausing " + mResumedActivity); // startPausingLocked() method is executed first pausing |= startPausingLocked(userLeaving, false, next, false); } ... ... ActivityStack lastStack = mStackSupervisor.getLastStack(); if (next.app != null && next.app.thread != null) { ... ... synchronized(mWindowManager.getWindowManagerLock()) { ... ... try { ... ... } catch (Exception e) { ... ... // Execute the startSpecificActivityLocked() method mStackSupervisor.startSpecificActivityLocked(next, true, false); return true; } } try { next.completeResumeLocked(); } catch (Exception e) { requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null, "resume-exception", true); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; } } else { ... ... // Execute the startSpecificActivityLocked() method mStackSupervisor.startSpecificActivityLocked(next, true, true); } if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); return true; }
In the resumeTopActivityInnerLocked method, it is used to determine whether an Activity is in the Resume state.
If there is one, the Activity is first asked to execute the Pausing process (Launcher's onPause process in this case) and then the startSpecific ActivityLocked method is executed to start the Activity that needs to be started.
2.21 ActivityStack.startPausingLocked
Let's first analyze the startPausingLocked() source code. The startSpecificActivityLocked() startSpecificActivityLocked () is discussed in the third section.
// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java // Execution of onPause method by stack top Activity final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, boolean pauseImmediately) { ... ... ActivityRecord prev = mResumedActivity; ... ... // Assign prev to mPausingActivity, which is used during Activity startup. // This is actually the assignment of mResumedActivity to mPausingActivity, our Launcher. mPausingActivity = prev; ... ... if (prev.app != null && prev.app.thread != null) { try { EventLogTags.writeAmPauseActivity(prev.userId, System.identityHashCode(prev), prev.shortComponentName, "userLeaving=" + userLeaving); mService.updateUsageStats(prev, false); /* * Android P Client Lifecycle Manager and Client Transaction Handler are introduced here to assist. * Manage the Activity life cycle, which sends EXECUTE_TRANSACTION messages * Continue processing in ActivityThread.H. * PauseActivityItem is implemented through the scheduleTransaction method of ClientLifecycle Manager * Events are added to the execution plan to start the pausing process at the top of the stack. */ mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, prev.configChangeFlags, pauseImmediately)); } catch (Exception e) { // Ignore exception, if process died other code will cleanup. Slog.w(TAG, "Exception thrown during pause", e); mPausingActivity = null; mLastPausedActivity = null; mLastNoHistoryActivity = null; } } else { mPausingActivity = null; mLastPausedActivity = null; mLastNoHistoryActivity = null; } ... ... }
2.22 ClientLifecycleManager.scheduleTransaction
// frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java class ClientLifecycleManager { void scheduleTransaction(ClientTransaction transaction) throws RemoteException { final IApplicationThread client = transaction.getClient(); transaction.schedule(); if (!(client instanceof Binder)) { transaction.recycle(); } } ... ... } // frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java public class ClientTransaction implements Parcelable, ObjectPoolItem { /** Target client. */ private IApplicationThread mClient; public void schedule() throws RemoteException { mClient.scheduleTransaction(this); } }
The mClient of ClientTransaction.schedule method is an IApplicationThread type. The internal class ApplicationThread of ActivityThread derives this interface class and implements the corresponding method. So jump directly to the scheduleTransaction method in Application Thread.
2.23 ActivityThread.scheduleTransaction
// frameworks/base/core/java/android/app/ActivityThread.java public final class ActivityThread extends ClientTransactionHandler { private class ApplicationThread extends IApplicationThread.Stub { ... ... public void scheduleTransaction(ClientTransaction transaction) throws RemoteException { ActivityThread.this.scheduleTransaction(transaction); } } }
2.24 Process Summary
2.25 ClientTransactionHandler.scheduleTransaction
The scheduleTransaction method is not defined in the ActivityThread class, so it calls the scheduleTransaction method of its parent ClientTransactionHandler.
// frameworks/base/core/java/android/app/ClientTransactionHandler.java public abstract class ClientTransactionHandler { abstract void sendMessage(int what, Object obj); void scheduleTransaction(ClientTransaction transaction) { transaction.preExecute(this); // sendMessage method is called, which is an abstract method. // Its implementation is in ActivityThread, a derived class of ClientTransactionHandler. sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); } }
2.26 ActivityThread.sendMessage
// frameworks/base/core/java/android/app/ActivityThread.java public final class ActivityThread extends ClientTransactionHandler { private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this); void sendMessage(int what, Object obj) { sendMessage(what, obj, 0, 0, false); } private void sendMessage(int what, Object obj, int arg1) { sendMessage(what, obj, arg1, 0, false); } private void sendMessage(int what, Object obj, int arg1, int arg2) { sendMessage(what, obj, arg1, arg2, false); } private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { Message msg = Message.obtain(); msg.what = what; msg.obj = obj; msg.arg1 = arg1; msg.arg2 = arg2; if (async) { msg.setAsynchronous(true); } // The ActivityThread.sendMessage method sends the message to Hadler, whose internal name is H. mH.sendMessage(msg); } class H extends Handler { public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case EXECUTE_TRANSACTION: final ClientTransaction transaction = (ClientTransaction) msg.obj; // An instance of Handler H is called after receiving the EXECUTE_TRANSACTION message // The TransactionExecutor.execute method switches the Activity state. mTransactionExecutor.execute(transaction); if (isSystem()) { transaction.recycle(); } // TODO(lifecycler): Recycle locally scheduled transactions. break; } } } }
2.27 TransactionExecutor.execute
// frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java public class TransactionExecutor { public void execute(ClientTransaction transaction) { final IBinder token = transaction.getActivityToken(); log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token); executeCallbacks(transaction); // Important Method 1 executeLifecycleState(transaction); // Important Method 2 mPendingActions.clear(); log("End resolving transaction"); } // Important Method 1 public void executeCallbacks(ClientTransaction transaction) { final List<ClientTransactionItem> callbacks = transaction.getCallbacks(); if (callbacks == null) { // No callbacks to execute, return early. return; } final int size = callbacks.size(); for (int i = 0; i < size; ++i) { final ClientTransactionItem item = callbacks.get(i); ... ... item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); ... ... } } // Important Method 2 /** Transition to the final state if requested by the transaction. */ private void executeLifecycleState(ClientTransaction transaction) { final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest(); ... ... // The state before the current life cycle state is executed cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */); // Execute the final transition with proper parameters. lifecycleItem.execute(mTransactionHandler, token, mPendingActions); lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions); } }
In the ActivityStack.startPausingLocked method, scheduleTransaction passes the PauseActivityItem object, so the execute method called in the executeLifecycleState method is actually the PauseActivityItem.execute method.
2.28 PauseActivityItem.execute
// frameworks/base/core/java/android/app/servertransaction/PauseActivityItem.java public class PauseActivityItem extends ActivityLifecycleItem { @Override public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { // Jump to the ActivityThread.handlePauseActivity method client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions, "PAUSE_ACTIVITY_ITEM"); } }
2.29 ActivityThread.handlePauseActivity
// frameworks/base/core/java/android/app/ActivityThread.java @Override public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, String reason) { ActivityClientRecord r = mActivities.get(token); if (r != null) { ... ... performPauseActivity(r, finished, reason, pendingActions); ... ... } }
2.30 ActivityThread.performPauseActivity
// frameworks/base/core/java/android/app/ActivityThread.java final Bundle performPauseActivity(IBinder token, boolean finished, String reason, PendingTransactionActions pendingActions) { ActivityClientRecord r = mActivities.get(token); return r != null ? performPauseActivity(r, finished, reason, pendingActions) : null; } private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason, PendingTransactionActions pendingActions) { ... ... performPauseActivityIfNeeded(r, reason); ... ... return shouldSaveState ? r.state : null; }
2.31 ActivityThread.performPauseActivityIfNeeded
// frameworks/base/core/java/android/app/ActivityThread.java private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) { if (r.paused) { // You are already paused silly... return; } try { r.activity.mCalled = false; mInstrumentation.callActivityOnPause(r.activity); // Key methodologies if (!r.activity.mCalled) { throw new SuperNotCalledException("Activity " + safeToComponentShortString(r.intent) + " did not call through to super.onPause()"); } } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException("Unable to pause activity " + safeToComponentShortString(r.intent) + ": " + e.toString(), e); } } r.setState(ON_PAUSE); }
2.32 Instrumentation.callActivityOnPause
// frameworks/base/core/java/android/app/Instrumentation.java public void callActivityOnPause(Activity activity) { activity.performPause(); // Direct invocation of Activity.performPause method }
2.33 Activity.performPause
// frameworks/base/core/java/android/app/Activity.java public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, WindowControllerCallback, AutofillManager.AutofillClient { final void performPause() { ... ... onPause(); ... ... } }
Summary of 2.34 Process
So far, Launcher's onPause() process analysis is over! At the same time, we need to understand that the onPause method of Activity at the top of the stack is the first one to be executed when starting an activity.
III. Starting the Process
Launcher's onPause() process is analyzed. Next, let's look at the startSpecificActivityLocked() method for starting a new process. In this method, we will determine whether App has been started based on the existence of processes and threads.
3.1 ActivityStackSupervisor.startSpecificActivityLocked
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true); getLaunchTimeTracker().setLaunchTime(r); // If the app exists and has been started if (app != null && app.thread != null) { try { if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0 || !"android".equals(r.info.packageName)) { app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode, mService.mProcessStats); } realStartActivityLocked(r, app, andResume, checkConfig); return; } catch (RemoteException e) { Slog.w(TAG, "Exception when starting activity " + r.intent.getComponent().flattenToShortString(), e); } } // Start a new process with mService as Activity Manager Service mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }
If started, the ActivityManagerService.realStartActivityLocked method is called to continue processing.
If it is not started, the ActivityManagerService.startProcessLocked method is called to create a new process process process.
3.2 ActivityManagerService.startProcessLocked -01
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType, hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */); }
3.3 ActivityManagerService.startProcessLocked -02
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { ... ... final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride); }
3.3 ActivityManagerService.startProcessLocked -03
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java private final boolean startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride) { return startProcessLocked(app, hostingType, hostingNameStr, false /* disableHiddenApiChecks */, abiOverride); }
3.4 ActivityManagerService.startProcessLocked -04
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java private final boolean startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) { try { ... ... return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); } catch (RuntimeException e) { forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, UserHandle.getUserId(app.userId), "start failure"); return false; } }
3.5 ActivityManagerService.startProcessLocked -05
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { ... ... final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); ... ... }
3.6 ActivityManagerService.startProcess
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java private ProcessStartResult startProcess(String hostingType, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { try { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName); checkTime(startTime, "startProcess: asking zygote to start proc"); final ProcessStartResult startResult; if (hostingType.equals("webview_service")) { startResult = startWebView(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } else { // Execute the Process.start method startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); } checkTime(startTime, "startProcess: returned from zygote!"); return startResult; } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } }
At this point, we understand that the ActivityManagerService.startProcessLocked method, after several jumps, will eventually create a process for the application through the Process.start method.
The process creation process and source code analysis are not discussed here. stay [Android'Process Threads'] Chat about how "processes" are created In this article, we have made a detailed analysis!
IV. Activity process
In our process-created blog, we discussed that the source code will eventually execute to the ActivityThread.main method to initialize the main thread.
4.1 Initialize the main thread
// frameworks/base/core/java/android/app/ActivityThread.java public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); CloseGuard.setEnabled(false); Environment.initForCurrentUser(); EventLogger.setReporter(new EventLoggingReporter()); final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); // Create the main thread looper long startSeq = 0; if (args != null) { for (int i = args.length - 1; i >= 0; --i) { if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) { startSeq = Long.parseLong( args[i].substring(PROC_START_SEQ_IDENT.length())); } } } ActivityThread thread = new ActivityThread(); // Initialize ActivityThread thread.attach(false, startSeq); // attach to system process if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Looper.loop(); // The main thread starts and enters the loop state throw new RuntimeException("Main thread loop unexpectedly exited"); }
4.2 Start Activity
// frameworks/base/core/java/android/app/ActivityThread.java private void attach(boolean system, long startSeq) { sCurrentActivityThread = this; mSystemThread = system; if (!system) { ... ... final IActivityManager mgr = ActivityManager.getService(); try { // Bind an Application for this application through Activity Manager Service mgr.attachApplication(mAppThread, startSeq); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } // Add a garbage collector, which will be in the run method whenever the system triggers garbage collection // To calculate how much memory the application uses, if more than three-quarters of the total, it will attempt to free memory. BinderInternal.addGcWatcher(new Runnable() { @Override public void run() { if (!mSomeActivitiesChanged) { return; } Runtime runtime = Runtime.getRuntime(); long dalvikMax = runtime.maxMemory(); long dalvikUsed = runtime.totalMemory() - runtime.freeMemory(); if (dalvikUsed > ((3*dalvikMax)/4)) { if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024) + " total=" + (runtime.totalMemory()/1024) + " used=" + (dalvikUsed/1024)); mSomeActivitiesChanged = false; try { mgr.releaseSomeActivities(mAppThread); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } }); } else { ... ... } ... ... // Adding a config callback to the root View to receive information about config changes ViewRootImpl.addConfigCallback(configChangedCallback); }
4.2.1 ActivityManagerService.attachApplication
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java @Override public final void attachApplication(IApplicationThread thread, long startSeq) { synchronized (this) { int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid, callingUid, startSeq); Binder.restoreCallingIdentity(origId); } }
4.2.2 ActivityManagerService.attachApplicationLocked
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java private final boolean attachApplicationLocked(IApplicationThread thread, int pid, int callingUid, long startSeq) { ... ... // See if the top visible activity is waiting to run in this process... if (normalMode) { try { if (mStackSupervisor.attachApplicationLocked(app)) { didSomething = true; } } catch (Exception e) { Slog.wtf(TAG, "Exception thrown launching activities in " + app, e); badApp = true; } } ... ... return true; }
4.3 ActivityStackSupervisor.attachApplicationLocked
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java boolean attachApplicationLocked(ProcessRecord app) throws RemoteException { final String processName = app.processName; boolean didSomething = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx); for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = display.getChildAt(stackNdx); if (!isFocusedStack(stack)) { continue; } stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList); final ActivityRecord top = stack.topRunningActivityLocked(); final int size = mTmpActivityList.size(); for (int i = 0; i < size; i++) { final ActivityRecord activity = mTmpActivityList.get(i); if (activity.app == null && app.uid == activity.info.applicationInfo.uid && processName.equals(activity.processName)) { try { // Execute the realStartActivityLocked method if (realStartActivityLocked(activity, app, top == activity /* andResume */, true /* checkConfig */)) { didSomething = true; } } catch (RemoteException e) { Slog.w(TAG, "Exception in new application when starting activity " + top.intent.getComponent().flattenToShortString(), e); throw e; } } } } } if (!didSomething) { ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } return didSomething; }
4.4 ActivityStackSupervisor.realStartActivityLocked
Real Start Activity Locked is a method called to start an activity when the application process has been started.
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { try { ... ... try { ... ... final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread, r.appToken); // Add the callback of LaunchActivityItem to the ClientTransaction object clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), System.identityHashCode(r), r.info, mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, mService.isNextTransitionForward(), profilerInfo)); final ActivityLifecycleItem lifecycleItem; // Setting the current life cycle state if (andResume) { lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward()); } else { lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); // Call the ClientLifecycle Manager. scheduleTransaction method mService.getLifecycleManager().scheduleTransaction(clientTransaction); ... ... }
After calling the ClientLifecycle Manager. scheduleTransaction method, we have already analyzed how to execute it, but we will not analyze it here.
Let's look at the LaunchActivityItem.execute method after executing callback.
4.5 LaunchActivityItem.execute
// frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java @Override public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, mPendingNewIntents, mIsForward, mProfilerInfo, client); // Call the ActivityThread.handleLaunchActivity method client.handleLaunchActivity(r, pendingActions, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }
4.6 ActivityThread.handleLaunchActivity
// frameworks/base/core/java/android/app/ActivityThread.java public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { ... ... final Activity a = performLaunchActivity(r, customIntent); ... ... }
4.7 ActivityThread.performLaunchActivity
// frameworks/base/core/java/android/app/ActivityThread.java private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } // Initialize ComponentName ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } // Initialize ContextImpl and Activeness ContextImpl appContext = createBaseContextForActivity(r); Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); if (r.state != null) { r.state.setClassLoader(cl); } } catch (Exception e) { ... ... } try { // Initialize Application Application app = r.packageInfo.makeApplication(false, mInstrumentation); if (activity != null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (r.overrideConfig != null) { config.updateFrom(r.overrideConfig); } Window window = null; if (r.mPendingRemoveWindow != null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; r.mPendingRemoveWindow = null; r.mPendingRemoveWindowManager = null; } appContext.setOuterContext(activity); activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback); if (customIntent != null) { activity.mIntent = customIntent; } r.lastNonConfigurationInstances = null; checkAndBlockForNetworkAccess(); activity.mStartedActivity = false; // Setting the Theme of Activity int theme = r.activityInfo.getThemeResource(); if (theme != 0) { activity.setTheme(theme); } activity.mCalled = false; // Call Instrumentation.callActivityOnCreate method if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } if (!activity.mCalled) { ... ... r.activity = activity; } r.setState(ON_CREATE); mActivities.put(r.token, r); } catch (SuperNotCalledException e) { ... ... } return activity; }
4.8 Instrumentation.callActivityOnCreate
// frameworks/base/core/java/android/app/Instrumentation.java public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) { prePerformCreate(activity); activity.performCreate(icicle, persistentState); // Execute this method postPerformCreate(activity); }
4.9 Activity.performCreate
// frameworks/base/core/java/android/app/Activity.java final void performCreate(Bundle icicle, PersistableBundle persistentState) { ... ... if (persistentState != null) { onCreate(icicle, persistentState); } else { onCreate(icicle); } ... ... }
At this point, when executeCallbacks() is finished, the executeLifecycleState method is started, and the cycleToPath method is executed first.
4.10 TransactionExecutor.cycleToPath
// frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState) { final int start = r.getLifecycleState(); log("Cycle from: " + start + " to: " + finish + " excludeLastState:" + excludeLastState); final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState); performLifecycleSequence(r, path); }
4.11 TransactionExecutor.performLifecycleSequence
// frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java private void performLifecycleSequence(ActivityClientRecord r, IntArray path) { final int size = path.size(); for (int i = 0, state; i < size; i++) { state = path.get(i); log("Transitioning to state: " + state); // The life cycle state is from ON_CREATE state to ON_RESUME state, with an ON_START state in the middle. // So the ActivityThread.handleStartActivity method is executed. switch (state) { case ON_CREATE: mTransactionHandler.handleLaunchActivity(r, mPendingActions, null /* customIntent */); break; case ON_START: mTransactionHandler.handleStartActivity(r, mPendingActions); break; case ON_RESUME: mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */, r.isForward, "LIFECYCLER_RESUME_ACTIVITY"); break; case ON_PAUSE: mTransactionHandler.handlePauseActivity(r.token, false /* finished */, false /* userLeaving */, 0 /* configChanges */, mPendingActions, "LIFECYCLER_PAUSE_ACTIVITY"); break; case ON_STOP: mTransactionHandler.handleStopActivity(r.token, false /* show */, 0 /* configChanges */, mPendingActions, false /* finalStateRequest */, "LIFECYCLER_STOP_ACTIVITY"); break; case ON_DESTROY: mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */, 0 /* configChanges */, false /* getNonConfigInstance */, "performLifecycleSequence. cycling to:" + path.get(size - 1)); break; case ON_RESTART: mTransactionHandler.performRestartActivity(r.token, false /* start */); break; default: throw new IllegalArgumentException("Unexpected lifecycle state: " + state); } } }
4.12 ActivityThread.handleStartActivity
// frameworks/base/core/java/android/app/ActivityThread.java public void handleStartActivity(ActivityClientRecord r, PendingTransactionActions pendingActions) { ... ... // Start activity.performStart("handleStartActivity"); r.setState(ON_START); ... ... }
4.13 Activity.performStart
// frameworks/base/core/java/android/app/Activity.java final void performStart(String reason) { ... ... mInstrumentation.callActivityOnStart(this); ... ... }
4.14 Instrumentation.callActivityOnStart
// frameworks/base/core/java/android/app/Instrumentation.java public void callActivityOnStart(Activity activity) { // After many jumps, the Activity.onStart method is finally called activity.onStart(); }
After executing cycleToPath, start executing the ResumeActivityItem.execute method.
4.15 ResumeActivityItem.execute
// frameworks/base/core/java/android/app/servertransaction/ResumeActivityItem.java public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward, "RESUME_ACTIVITY"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }
4.16 ActivityThread.handleResumeActivity
// frameworks/base/core/java/android/app/ActivityThread.java public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { ... ... // TODO Push resumeArgs into the activity for consideration final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); if (r == null) { // We didn't actually resume the activity, so skipping any follow-up actions. return; } ... ... if (localLOGV) Slog.v(TAG, "Scheduling idle handler for " + r); // The method here will be explained in the end, which involves the onStop() method. Looper.myQueue().addIdleHandler(new Idler()); }
4.17 ActivityThread.performResumeActivity
// frameworks/base/core/java/android/app/ActivityThread.java public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, String reason) { ... ... try { r.activity.onStateNotSaved(); r.activity.mFragments.noteStateNotSaved(); checkAndBlockForNetworkAccess(); if (r.pendingIntents != null) { deliverNewIntents(r, r.pendingIntents); r.pendingIntents = null; } if (r.pendingResults != null) { deliverResults(r, r.pendingResults, reason); r.pendingResults = null; } // Execute the performResume method r.activity.performResume(r.startsNotResumed, reason); r.state = null; r.persistentState = null; r.setState(ON_RESUME); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException("Unable to resume activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } return r; }
4.18 Activity.performResume
// frameworks/base/core/java/android/app/Activity.java final void performResume(boolean followedByPause, String reason) { performRestart(true /* start */, reason); ... ... // mResumed is set by the instrumentation mInstrumentation.callActivityOnResume(this); ... ... }
4.19 Instrumentation.callActivityOnResume
// frameworks/base/core/java/android/app/Instrumentation.java public void callActivityOnResume(Activity activity) { activity.mResumed = true; // Eventually call the Activity.onResume method activity.onResume(); ... ... }
So far, Activity has been started.
5. Stack top activity onStop
When we discussed the ActivityThread.handleResumeActivity source code, the last line of code was not discussed.
// frameworks/base/core/java/android/app/ActivityThread.java public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { ... ... final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); ... ... // This Handler is executed when MessageQueue is idle, after executing the onResume() method of the current Activity Looper.myQueue().addIdleHandler(new Idler()); }
Why discuss this line of code separately, because the onPause(), onCreate(), onStart(), onResume() of the new Activity are analyzed above, but an onStop() lifecycle of the top Activity is missing. This method is handled in this line of code.
5.1 Idler
// frameworks/base/core/java/android/app/ActivityThread.java private class Idler implements MessageQueue.IdleHandler { @Override public final boolean queueIdle() { ... ... if (a != null) { mNewActivities = null; IActivityManager am = ActivityManager.getService(); ActivityClientRecord prev; do { if (a.activity != null && !a.activity.mFinished) { try { // Call the ActivityManagerService.activityIdle method am.activityIdle(a.token, a.createdConfig, stopProfiling); a.createdConfig = null; } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } prev = a; a = a.nextIdle; prev.nextIdle = null; } while (a != null); } ... ... return false; } }
5.2 ActivityManagerService.activityIdle
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) { final long origId = Binder.clearCallingIdentity(); synchronized (this) { ActivityStack stack = ActivityRecord.getStackLocked(token); if (stack != null) { // Call the ActivityStackSupervisor.activityIdleInternalLocked method ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */, false /* processPausingActivities */, config); if (stopProfiling) { if ((mProfileProc == r.app) && mProfilerInfo != null) { clearProfilerLocked(); } } } } Binder.restoreCallingIdentity(origId); }
5.3 ActivityStackSupervisor.activityIdleInternalLocked
// frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout, boolean processPausingActivities, Configuration config) { for (int i = 0; i < NS; i++) { r = stops.get(i); final ActivityStack stack = r.getStack(); if (stack != null) { if (r.finishing) { stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false, "activityIdleInternalLocked"); } else { stack.stopActivityLocked(r); } } } ... ... return r; }
5.4 ActivityStack.stopActivityLocked
// frameworks/base/services/core/java/com/android/server/am/ActivityStack.java final void stopActivityLocked(ActivityRecord r) { ... ... if (r.app != null && r.app.thread != null) { adjustFocusedActivityStack(r, "stopActivity"); r.resumeKeyDispatchingLocked(); try { ... ... mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken, StopActivityItem.obtain(r.visible, r.configChangeFlags)); if (shouldSleepOrShutDownActivities()) { r.setSleeping(true); } Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r); mHandler.sendMessageDelayed(msg, STOP_TIMEOUT); } catch (Exception e) { ... ... } } }
I saw ClientLifecycle Manager. scheduleTransaction method again. I have analyzed it many times before, and I will execute the StopActivityItem.execute method. After many jumps, I finally execute the Activity.onStop method.
5.5 StopActivityItem.execute
// frameworks/base/core/java/android/app/servertransaction/StopActivityItem.java @Override public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions, true /* finalStateRequest */, "STOP_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }
5.6 ActivityThread.handleStopActivity
// frameworks/base/core/java/android/app/ActivityThread.java @Override public void handleStopActivity(IBinder token, boolean show, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) { ... ... performStopActivityInner(r, stopInfo, show, true /* saveState */, finalStateRequest, reason); ... ... }
5.7 ActivityThread.performStopActivityInner
// frameworks/base/core/java/android/app/ActivityThread.java private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown, boolean saveState, boolean finalStateRequest, String reason) { if (r != null) { ... ... if (!keepShown) { callActivityOnStop(r, saveState, reason); } } }
5.8 ActivityThread.callActivityOnStop
// frameworks/base/core/java/android/app/ActivityThread.java private void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) { ... ... try { r.activity.performStop(false /*preserveWindow*/, reason); } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { ... ... } ... ... }
5.9 Activity.performStop
// frameworks/base/core/java/android/app/Activity.java final void performStop(boolean preserveWindow, String reason) { ... ... if (!mStopped) { ... ... mInstrumentation.callActivityOnStop(this); } }
5.10 Instrumentation.callActivityOnStop
// frameworks/base/core/java/android/app/Instrumentation.java public void callActivityOnStop(Activity activity) { activity.onStop(); }