There are two ways to start an Activity, one is the root Activity to start, and the other is the normal Activity to start. The root Activity can be understood as the first Activity that the application starts, or it can be understood directly as the application starts.
Launcher Request AMS process
Sequence diagram:
The startActivitySafely method of the Launcher is called when a desktop icon is clicked. FLAG_ACTIVITY_NEW_TASK Sets the Flag of the Intent that starts the Activity to FLAG_ACTIVITY_NEW_TASK so that it can be launched in a new task stack. The startActivity method is then called.
Follow the startActivity method, then go to the startActivityForResult method:
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
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());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else{... }}Copy the code
The mParent method is of type Activity, because the root Activity has not yet been created, so mParent is null. The execStartActivity method of the Instrumentation is then called.
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options){...try{ intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); int result = ActivityTaskManager.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;
}
Copy the code
This calls ActivityManager’s getService() method to get the AMS object, followed by its startActivity method. So let’s take a look at what does this getService method do
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
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);
returnam; }};Copy the code
GetService method call IActivityManagerSingleton the get method. Here we can see IActivityManagerSingleton is a Singleton class. Inside, you get a Service reference called Activity, which is an AMS reference of type IBinder. Then convert it to an object of type IActivityManager.
Is adopted here is that the AIDL, IActivityManager AIDL tool automatically generated at compile time, the file path for frameworkd/base/core/Java/android/app/IActivityManager AIDL. AIDL wasn’t used until Android8.0. So what you end up calling above is AMS’s startActivity method.
AMS calls to ApplicationThread
Sequence diagram:
Now let’s look at the method that finally calls AMS ‘startActivity method
@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) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
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) {
enforceNotIsolatedCaller("startActivity");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity".null);
// TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null.null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null.null, bOptions, false, userId, null.null."startActivityAsUser");
}
Copy the code
We can see the code and then call the startActivityAsUser method, startActivityAsUser method. The last parameter is UserHandle getCallingUserId (), the method to obtain the caller’s UserId, AMS follows this UserId to determine the caller’s permissions.
Let’s look at the implementation of startActivityAsUser, in which enforcenotiatedCaller is first called to check whether the caller process is isolated, and if it is, an exception is thrown. Then call mUserController. HandleIncomingUser method to judge whether the caller has permission, if not will throw an exception. The startActivityMayWait method of ActivityStarter is then called.
ActivityStarter, a new class added to Android 7.0, is a control class that loads activities, collects all the logic to determine how to convert intents and Flags into activities, and associates activities with tasks and stacks.
final int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, WaitResult outResult,
Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
IActivityContainer iContainer, TaskRecord inTask, String reason){... final ActivityRecord[] outRecord =new ActivityRecord[1]; int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, outRecord, container, inTask, reason); Binder.restoreCallingIdentity(origId); .returnres; }}Copy the code
Finally, the startActivityLocked method is called, with the penultimate parameter TaskRecord, which represents the stack on which to start AcElasticity. The last parameter represents the reason for starting.
Next, look at the startActivityLocked method
int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask, String reason) {
if (TextUtils.isEmpty(reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
}
mLastStartReason = reason;
mLastStartActivityTimeMs = System.currentTimeMillis();
mLastStartActivityRecord[0] = null;
mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
container, inTask);
if(outActivity ! =null) {
// mLastStartActivityRecord[0] is set in the call to startActivity above.
outActivity[0] = mLastStartActivityRecord[0];
}
return mLastStartActivityResult;
}
Copy the code
The reason () method checks if the passed reason is null, and if it is, it throws an exception. The startActivity method of ActivityStarter is then called.
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,
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
int err = ActivityManager.START_SUCCESS;
// Pull the optional Ephemeral Installer-only bundle out of the options early.final Bundle verificationBundle = options ! =null ? options.popAppVerificationBundle() : null;
ProcessRecord callerApp = null;
if(caller ! =null) {
callerApp = mService.getRecordForAppLocked(caller);
if(callerApp ! =null) {
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "+ intent.toString()); err = ActivityManager.START_PERMISSION_DENIED; }}... ActivityRecord r =newActivityRecord(mService, callerApp, callingPid, callingUid, callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode, componentSpecified, voiceSession ! =null,
mSupervisor, container, options, sourceRecord);
if(outActivity ! =null) {
outActivity[0] = r; }... doPendingActivityLaunchesLocked(false);
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
options, inTask, outActivity);
}
Copy the code
The IApplicationThread () method checks whether the caller pointing to the ApplicationThread object in the application Launcher is null. Then call AMS’s getRecordForAppLocked method to get the callerApp object representing the Launcher process, which is of type ProcessRecord and describes the application process. ActivityRecord is used to describe an Activity and record all information about the Activity. Next, with the parameters obtained by the callerApp, create an ActivityRecord that describes the Activity to start. The newly created ActivityRecord is then assigned to the first outActivity element. This outActivity is passed as an argument to the startActivity method.
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 {
mService.mWindowManager.deferSurfaceLayout();
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity);
} finally {
// If we are not able to proceed, disassociate the activity from the task. Leaving an
// activity in an incomplete state can lead to issues, such as performing operations
// without a window container.
if(! ActivityManager.isStartResultSuccessful(result) && mStartActivity.getTask() ! =null) { mStartActivity.getTask().removeActivity(mStartActivity); } mService.mWindowManager.continueSurfaceLayout(); }...return result;
}
Copy the code
Here we continue to call the startActivityUnchecked method
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity){...// Should this be considered a new task?
int result = START_SUCCESS;
if (mStartActivity.resultTo == null && mInTask == null&&! mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) ! =0) {
newTask = true;
result = setTaskFromReuseOrCreateNewTask(
taskToAffiliate, preferredLaunchStackId, topStack);
} else if(mSourceRecord ! =null) {
result = setTaskFromSourceRecord();
} else if(mInTask ! =null) {
result = setTaskFromInTask();
} 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.
setTaskToCurrentTopOrCreateNewTask();
}
if(result ! = START_SUCCESS) {returnresult; }...if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if(! mTargetStack.isFocusable() || (topTaskActivity ! =null&& topTaskActivity.mTaskOverlay && mStartActivity ! = topTaskActivity)) { mTargetStack.ensureActivitiesVisibleLocked(null.0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
// will not update the focused stack. If starting the new activity now allows the
// task stack to be focusable, then ensure that we now update the focused stack
// accordingly.
if(mTargetStack.isFocusable() && ! mSupervisor.isFocusedStack(mTargetStack)) { mTargetStack.moveToFront("startActivityUnchecked"); } mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); }}else{ mTargetStack.addRecentActivityLocked(mStartActivity); }... }Copy the code
This approach deals primarily with stack management-related logic. The Flags for the Intent of the root Activity is FLAG_ACTIVITY_NEW_TASK, which satisfies the initial criteria. Call setTaskFromReuseOrCreateNewTask method, the method will create a new internal TaskRecord, used to describe the Activity task stack. Then call ActivityStackSupervisor resumeFocusedStackTopActivityLocked method.
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if(targetStack ! =null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null|| r.state ! = RESUMED) { mFocusedStack.resumeTopActivityUncheckedLocked(null.null);
} else if (r.state == RESUMED) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
return false;
}
Copy the code
The topRunningActivityLocked() method of mFocusedStack is called to get a non-stopped ActivityRecord at the top of the stack for the Activity to be started. If ActivityRecord is null or not RESUMED state, will call ActivityStack resumeTopActivityUncheckedLocked method.
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);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
// When resuming the top activity, it may be necessary to pause the top activity (for
// example, returning to the lock screen. We suppress the normal pause logic in
// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
// We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
// any necessary pause logic occurs.
mStackSupervisor.checkReadyForSleepLocked();
return result;
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options){... mStackSupervisor.startSpecificActivityLocked(next,true.true); . }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);
r.getStack().setLaunchTime(r);
if(app ! =null&& app.thread ! =null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true.0."activity", r.intent.getComponent(), false.false.true);
}
Copy the code
Will call to startSpecificActivityLocked method, the method of first to start the process of the Activity of information. It then checks to see if the process is started, and if it is, it enters the check and calls realStartActivityLocked. The second argument to realStartActivityLocked is the process information for the Activity to start (the app obtained earlier).
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global and
// override configs.mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, ! andResume, mService.isNextTransitionForward(), profilerInfo); . }Copy the code
App. thread refers to IApplicationThread, whose implementation class is the inner class ApplicationThread of ActivityThread. App refers to the process in which the Activity is to be launched. This code calls the scheduleLaunchActivity method to start the Activity in the target application process. The current code runs in AMS and communicates with the application through ApplicationThreads, which bridge the communication between the AMS process and the application process.
ActivityThread start-up Activity
Sequence diagram:
Next, we arrive at the scheduleLaunchActivity method of ApplicationThread
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
private void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0.0.false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + "" + mH.codeToString(what)
+ ":" + arg1 + "/" + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
Copy the code
In this method, the parameters that start the Activity are encapsulated as an ActivityClientRecord. Then send a LAUNCH_ACTIVITY message to H using the sendMessage method, passing the ActivityClientRecord as well.
MH is class H, an inner class of ActivityThread that inherits Handler, the logic used to process the main thread. Since the execution of the ApplicationThread is in the Bindler thread, the thread is cut back to the resident thread by H.
Now what happens in H
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100; . publicvoid handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null."LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break; . }Object obj = msg.obj;
if (obj instanceof SomeArgs) {
((SomeArgs) obj).recycle();
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: "+ codeToString(msg.what)); }... }Copy the code
Here we take the ActivityClientRecord, use the getPackageInfoNoCheck method to get an instance of LoadedApk, and assign this instance to the packageInfo parameter of ActivityClientRecord. LoadedApk is a class that describes the APK package information of the application to start the Activity. It contains all information about the currently LoadedApk. Finally, call the handleLaunchActivity method.
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason){... Activity a = performLaunchActivity(r, customIntent);if(a ! =null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward, ! r.activity.mFinished && ! r.startsNotResumed, r.lastProcessedSeq, reason);if(! r.activity.mFinished && r.startsNotResumed) { performPauseActivityIfNeeded(r, reason);if(r.isPreHoneycomb()) { r.state = oldState; }}}else {
// If there was an error, for any reason, tell the activity manager to stop us.
try {
ActivityManager.getService()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throwex.rethrowFromSystemServer(); }}}Copy the code
Call performLaunchActivity to start the Activity, and then call the handleResumeActivity method to set the Activity state to Resume. If calling the performLaunchActivity method returns null, AMS will stop the Activity. Let’s look at what the FormLaunchActivity method does.
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
// Get the Activity description class, ActivityInfo. ActivityInfo is used to store code and AndroidManifest Settings
// Set Activity and Receiver node information, such as Activity theme and launchMode.
ActivityInfo aInfo = r.activityInfo;
// Check whether packageInfo is null. If null, get LoadedApk again and assign it to packageInfo.
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
// Create the ComponentName class needed to start the Activity. In ComponentName, save the name of the Activity package and
/ / the name of the class
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);
}
// Create a context to start the Activity. So here's ContextImpl for Activiyy.
// The ContextImpl of the Application is created when the Application is created.
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
// Create an Activity instance based on className for ComponentName.
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) {
if(! mInstrumentation.onException(activity, e)) {throw new RuntimeException(
"Unable to instantiate activity " + component
+ ":"+ e.toString(), e); }}try {
// Create an Application instance that internally calls Application's onCreate method.
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);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if(r.mPendingRemoveWindow ! =null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
appContext.setOuterContext(activity);
// Initializing the Activity will check the u you feel love your Window object associated with the 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;
int theme = r.activityInfo.getThemeResource();
// Set the Activity's theme
if(theme ! =0) {
activity.setTheme(theme);
}
activity.mCalled = false;
Call the callActivityOnCreate method in Instrumentation to start the Activity
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if(! activity.mCalled) {throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
if(! r.activity.mFinished) { activity.performStart(); r.stopped =false;
}
if(! r.activity.mFinished) {if (r.isPersistable()) {
if(r.state ! =null|| r.persistentState ! =null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); }}else if(r.state ! =null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); }}if(! r.activity.mFinished) { activity.mCalled =false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
if(! activity.mCalled) {throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if(! mInstrumentation.onException(activity, e)) {throw new RuntimeException(
"Unable to start activity " + component
+ ":"+ e.toString(), e); }}return activity;
}
Copy the code
This method contains a lot of things, the process is written into the code, see for yourself. Let’s look at the more important makeApplication method of the above method
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation){...try{...// Create ContextImpl class and set APK's Resources in ContextImpl. Here,
//ContextImpl belongs to the Application, not the Activity.
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// Create the Application class and bind it with ContextImpl
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
...
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
if(instrumentation ! =null) {
try {
// Call Application's onCreate method
instrumentation.callApplicationOnCreate(app);
} catch(Exception e) { ... }}...return app;
}
Copy the code
The method creates the Application, ContextImpl, binds them to each other, and calls the Application’s onCreate method.
Let’s look at the attach method for our Activity
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
// Create an implementation of Window class PhoneWindow
mWindow = new PhoneWindow(this.window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if(info.softInputMode ! = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); }if(info.uiOptions ! =0) {
mWindow.setUiOptions(info.uiOptions);
}
// Assign parametersmUiThread = Thread.currentThread(); mMainThread = aThread; .// Create WindowManager and set it to WindowmWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) ! =0); . }Copy the code
Attach is the method in the Activity that creates the PhoneWindow and assigns the mWindow parameter to the Activity, and then sets the WindowManager to the mWindow.
Finally, take a look at the callActivityOnCreate method that starts the Instrumentation of the Activity
public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
postPerformCreate(activity);
}
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
restoreHasCurrentPermissionRequest(icicle);
onCreate(icicle, persistentState);
mActivityTransitionState.readState(icicle);
performCreateCommon();
}
Copy the code
The onCreate method of the Activity is called in the callActivityOnCreate method, at which point the Activity starts.