您的位置首页  桂林文化  影视

Android常用组件—Activity启动详细流程

            Android常用组件—Activity启动详细流程

一、Activity请求启动

我们以startActivity这种来分析

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n6" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Intent intent=new Intent(MainActivity.this,TargetActivity.class);

startActivity(intent);</pre>

经过startActivity-->startActivityForResult-->execStartActivity,最终会调用Instrumentation的execStartActivity方法

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n8" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public ActivityResult execStartActivity(

Context who, IBinder contextThread, IBinder token, Activity target,

Intent intent, int requestCode, Bundle options) {

IApplicationThread whoThread = (IApplicationThread) contextThread;

Uri referrer = target != null ? target.onProvideReferrer() : null;

if (referrer != null) {

intent.putExtra(Intent.EXTRA_REFERRER, referrer);

}

.....

try {

intent.migrateExtraStreamToClipData();

intent.prepareToLeaveProcess(who);

//获取AMS的代理,启动Activity

int result = ActivityManagerNative.getDefault()

.startActivity(whoThread, who.getBasePackageName(), intent,

intent.resolveTypeIfNeeded(who.getContentResolver()),

token, target != null ? target.mEmbeddedID : null,

requestCode, 0, null, options);

//检查Activity是否启动成功,若失败给出是什么原因

checkStartActivityResult(result, intent);

} catch (RemoteException e) {

throw new RuntimeException("Failure from system", e);

}

return null;

}

}</pre>

这些参数的意思是:

this,为启动Activity的对象;

contextThread,为Binder对象,是主进程的context对象;

token,也是一个Binder对象,指向了服务端一个ActivityRecord对象;

target,为启动的Activity;

intent,启动的Intent对象;

requestCode,请求码;

options,参数;

先看checkStartActivityResult方法的实现

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n28" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public static void checkStartActivityResult(int res, Object intent) {

if (res >= ActivityManager.START_SUCCESS) {

return;

}

switch (res) {

case ActivityManager.START_INTENT_NOT_RESOLVED:

case ActivityManager.START_CLASS_NOT_FOUND:

if (intent instanceof Intent && ((Intent)intent).getComponent() != null)

throw new ActivityNotFoundException(

"Unable to find explicit activity class "

+ ((Intent)intent).getComponent().toShortString()

+ "; have you declared this activity in your AndroidManifest.xml?");

throw new ActivityNotFoundException(

"No Activity found to handle " + intent);

case ActivityManager.START_PERMISSION_DENIED:

throw new SecurityException("Not allowed to start activity "

+ intent);

case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:

throw new AndroidRuntimeException(

"FORWARD_RESULT_FLAG used while also requesting a result");

case ActivityManager.START_NOT_ACTIVITY:

throw new IllegalArgumentException(

"PendingIntent is not an activity");

case ActivityManager.START_NOT_VOICE_COMPATIBLE:

throw new SecurityException(

"Starting under voice control not allowed for: " + intent);

case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:

throw new IllegalStateException(

"Session calling startVoiceActivity does not match active session");

case ActivityManager.START_VOICE_HIDDEN_SESSION:

throw new IllegalStateException(

"Cannot start voice activity on a hidden session");

case ActivityManager.START_CANCELED:

throw new AndroidRuntimeException("Activity could not be started for "

+ intent);

default:

throw new AndroidRuntimeException("Unknown error code "

+ res + " when starting " + intent);

}

}</pre>

常见的ActivityNotFoundException,SecurityException等错日志就在这里报出来的;

OK,现在回到execStartActivity,内部调用了ActivityManagerNative.getDefault().startActivity,关于ActivityManagerNative已经说了很多了,相当于AMS服务端存根或者代理,其客户端是ActivityManagerNative的内部类ActivityManagerProxy,这里getDefault获取的就是ActivityManagerProxy对象,通过ActivityManagerProxy对象来使用AMS内部的一些服务,包括单不限于启动Activity

所以通过ActivityManagerProxy对象调用startActivity方法的实质是调用BinderProxy.transact向Binder驱动发送START_ACTIVITY_TRACSACTION命令,binder驱动将处理逻辑从Launcher所在的进程切换到AMS所在的SystemServer进程。OK,我们直接看ActivityManagerService的startActivity方法,不明白,建议看一下Binder的通信原理。

二、AMS处理Activity的启动请求

2.1、AMS处理Activity的启动请求

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n33" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> @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());

}</pre>

保持篇幅,以下步骤省略

ActvityiManagerService.startActivityAsUser() ActivityStackSupervisor.startActivityMayWait() ActivityStackSupervisor.startActivityLocked() ActivityStackSupervisor.startActivityUncheckedLocked() ActivityStackSupervisor.startActivityLocked() ActivityStackSupervisor.resumeTopActivitiesLocked() ActivityStackSupervisor.resumeTopActivityInnerLocked()

在resumeTopActivityInnerLocked的内部有如下代码

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n38" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> if (mResumedActivity != null) {

if (DEBUG_STATES) Slog.d(TAG_STATES,

"resumeTopActivityLocked: Pausing " + mResumedActivity);

pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);

}

</pre>

这表明在启动一个Activity的时候,前面一个Activity要执行onPause方法,onPause方法是怎么调用的呢?

2.2、AMS调用栈顶Activity的onPause

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n41" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,

boolean dontWait) {

......

if (mService.mHasRecents && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {

prev.updateThumbnailLocked(screenshotActivities(prev), null);

}

stopFullyDrawnTraceIfNeeded();

mService.updateCpuStats();

if (prev.app != null && prev.app.thread != null) {

if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);

try {

//调用ApplicationThread的schedulePauseActivity

prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,

userLeaving, prev.configChangeFlags, dontWait);

} catch (Exception e) {

......

}

}

......

}</pre>

这里先留一个问题, 我知道prev.app.thread是ApplicationThreadProxy对象,实际是调用了ApplicationThread的schedulePauseActivity方法,但是 AMS是怎么获取到prev.app.thread的呢?

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n43" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public final void schedulePauseActivity(IBinder token, boolean finished,

boolean userLeaving, int configChanges, boolean dontReport) {

sendMessage(

finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,

token,

(userLeaving ? 1 : 0) | (dontReport ? 2 : 0),

configChanges);

}

</pre>

关键就是最后调用了sendMessage(H.BIND_APPLICATION, data),发送了消息; 关于H这个类,其实是个Hander,我觉得它的作用就像是一个交通枢纽;H接收到这个Message之后,调用

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n45" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2, (msg.arg1&2) != 0);</pre>

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n46" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> private void handlePauseActivity(IBinder token, boolean finished,

boolean userLeaving, int configChanges, boolean dontReport) {

ActivityClientRecord r = mActivities.get(token);

.......

r.activity.mConfigChangeFlags |= configChanges;

performPauseActivity(token, finished, r.isPreHoneycomb());

.......

// Tell the activity manager we have paused.

if (!dontReport) {

try {

ActivityManagerNative.getDefault().activityPaused(token);

} catch (RemoteException ex) {

}

}

mSomeActivitiesChanged = true;

}

}</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n47" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,

boolean saveState) {

if (r.paused) {

.......

try {

.......

//调用Instrumentation的callActivityOnPause方法

mInstrumentation.callActivityOnPause(r.activity);

EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),

r.activity.getComponentName().getClassName());

if (!r.activity.mCalled) {

throw new SuperNotCalledException(

"Activity " + r.intent.getComponent().toShortString() +

" did not call through to super.onPause()");

}

} catch (SuperNotCalledException e) {

throw e;

} catch (Exception e) {

.......

}

}

r.paused = true;

.......

return !r.activity.mFinished && saveState ? r.state : null;

}</pre>

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n48" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public void callActivityOnPause(Activity activity) {

activity.performPause();

}

</pre>

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n49" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> final void performPause() {

mDoReportFullyDrawn = false;

mFragments.dispatchPause();

mCalled = false;

//onPause执行

onPause();

mResumed = false;

if (!mCalled && getApplicationInfo().targetSdkVersion

>= android.os.Build.VERSION_CODES.GINGERBREAD) {

throw new SuperNotCalledException(

"Activity " + mComponent.toShortString() +

" did not call through to super.onPause()");

}

mResumed = false;

}</pre>

分析到这里 onPause()终于执行了; 回到 handlePauseActivity方法中,在这个方法最后调用了ActivityManagerNative.getDefault().activityPaused(token)

2.3、ActivityManagerService的activityPaused方法执行

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n52" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> @Override

public final void activityPaused(IBinder token) {

final long origId = Binder.clearCallingIdentity();

synchronized(this) {

ActivityStack stack = ActivityRecord.getStackLocked(token);

if (stack != null) {

stack.activityPausedLocked(token, false);

}

}

Binder.restoreCallingIdentity(origId);

}</pre>

经过一些方法,最终会调用startSpecificActivityLocked

ActivityStack.activityPausedLocked() ActivityStack.completePauseLocked() ActivityStackSupervisor.resumeTopActivitiesLocked() ActivityStack.resumeTopActivityLocked() ActivityStack.resumeTopActivityInnerLocked () ActivityStack.startSpecificActivityLocked ()

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n56" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> 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.task.stack.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);

}

</pre>

如果需要启动的Activity所需要的应用进程是否已经启动,如果没有则执行realStartActivityLocked去启动Activity,否则去启动启动应用进程,相当于一个预启动的过程

2.4、应用进程创建

startProcessLocked是怎么执行的? SystemServer进程中Ams通过Socket与Zygote进程进行通信的,Zygote接收到AMS发起的创建进程的请求,会fork出一个子进程,并且反射调用这个进程中ActivityThread的main方法,在应用进程启动之后,ActivityThread的main方法就开始执行了

三、ActivityThread的main方法执行

在ActivityThread的main方法里调用thread.attach(false)

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n62" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public static void main(String[] args) {

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

SamplingProfilerIntegration.start();

......

Process.setArgV0("<pre-initialized>");

Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();

thread.attach(false);

if (sMainThreadHandler == null) {

sMainThreadHandler = thread.getHandler();

}

if (false) {

Looper.myLooper().setMessageLogging(new

LogPrinter(Log.DEBUG, "ActivityThread"));

}

// End of event ActivityThreadMain.

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");

}</pre>

对于上面main方法,相信很多人都看多很多遍了,接下来重点分析 thread.attach(false)这行代码

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n64" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> private void attach(boolean system) {

sCurrentActivityThread = this;

mSystemThread = system;

if (!system) {

.......

//获取ActivityManagerService在客户端的代理

IActivityManager mgr = ActivityManagerNative.getDefault();

try {

//实质是调用ActivityManagerService的attachApplication方法,目的是让ActivityManagerService通过ApplicationThread代理对象控制应用进程

mgr.attachApplication(mAppThread);

} catch (RemoteException ex) {

}

}

.......

}</pre>

在调用 mgr.attachApplication()的时候,将mAppThread对象传进去了

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n66" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> final ApplicationThread mAppThread = new ApplicationThread();</pre>

ApplicationThread继承了ApplicationThreadNative, 看一下ApplicationThreadNative里面的方法

内部调用了ActivityManagerNative.getDefault() .attachApplication,关于ActivityManagerNative已经说了很多了,相当于AMS服务端存根或者代理,其客户端是ActivityManagerNative的内部类ActivityManagerProxy,这里getDefault获取的就是ActivityManagerProxy对象,通过ActivityManagerProxy对象来使用AMS内部的一些服务,包括单不限于启动Activity

所以通过ActivityManagerProxy对象调用attachApplication方法的实质是调用BinderProxy.transact向Binder驱动发送ATTACH_APPLICATION_TRANSACTION命令,binder驱动将处理逻辑从APP应用进程所在的进程切换到AMS所在的SystemServer进程

OK,我们直接看ActivityManagerService的attachApplication方法:

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n69" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> @Override

public final void attachApplication(IApplicationThread thread) {

synchronized (this) {

int callingPid = Binder.getCallingPid();

final long origId = Binder.clearCallingIdentity();

attachApplicationLocked(thread, callingPid);

Binder.restoreCallingIdentity(origId);

}

}</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n70" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">private final boolean attachApplicationLocked(IApplicationThread thread,

int pid) {

ProcessRecord app;

if (pid != MY_PID && pid >= 0) {

synchronized (mPidsSelfLocked) {

//通过进程ID,获取进程的记录信息

app = mPidsSelfLocked.get(pid);

}

} else {

app = null;

}

if (app == null) {

Slog.w(TAG, "No pending application record for pid " + pid

+ " (IApplicationThread " + thread + "); dropping process");

EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);

if (pid > 0 && pid != MY_PID) {

//如果没有获取到,需要杀死该进程,MY_PID是系统进程

Process.killProcessQuiet(pid);

} else {

......

return false;

}

......

//获取进程名称

final String processName = app.processName;

try {

AppDeathRecipient adr = new AppDeathRecipient(

app, pid, thread);

thread.asBinder().linkToDeath(adr, 0);

app.deathRecipient = adr;

} catch (RemoteException e) {

app.resetPackageList(mProcessStats);

startProcessLocked(app, "link fail", processName);

return false;

}

EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);

//设置进程的OOM,adj等值

//还记得上面留下的那个问题吗,AMS是怎么获取到prev.app.thread的呢?就在这,prev.app是ProcessRecord对象,makeActive内部将thread对象赋值给prev.app.thread。可以自己查阅,这样AMS是可以查询进程记录的,进程记录中就有一个app.thread,若AMS要跟Activity通信直接获取prev.app.thread就可以了。

app.makeActive(thread, mProcessStats);

app.curAdj = app.setAdj = -100;

app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;

app.forcingToForeground = null;

updateProcessForegroundLocked(app, false, false);

app.hasShownUi = false;

app.debugging = false;

app.cached = false;

app.killedByAm = false;

//将attach之前的超时Meessage移除掉

mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);

List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;

......

try {

......

thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,

profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,

app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,

isRestrictedBackupMode || !normalMode, app.persistent,

new Configuration(mConfiguration), app.compat,

getCommonServicesLocked(app.isolated),

mCoreSettingsObserver.getCoreSettingsLocked());

updateLruProcessLocked(app, false, null);

app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();

} catch (Exception e) {

// todo: Yikes! What should we do? For now we will try to

// start another process, but that could easily get us in

// an infinite loop of restarting processes...

Slog.wtf(TAG, "Exception thrown during bind of " + app, e);

app.resetPackageList(mProcessStats);

app.unlinkDeathRecipient();

startProcessLocked(app, "bind fail", processName);

return false;

}

......

// 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;

}

}

// 执行等待进程而暂时挂起的Service

if (!badApp) {

try {

didSomething |= mServices.attachApplicationLocked(app, processName);

} catch (Exception e) {

Slog.wtf(TAG, "Exception thrown starting services in " + app, e);

badApp = true;

}

}

// 执行等待进程而暂时挂起的广播

if (!badApp && isPendingBroadcastProcessLocked(pid)) {

try {

didSomething |= sendPendingBroadcastsLocked(app);

} catch (Exception e) {

// If the app died trying to launch the receiver we declare it 'bad'

Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);

badApp = true;

}

}

......

if (!didSomething) {

//调整进程优先级adj的值

updateOomAdjLocked();

}

return true;

}</pre>

发现AMS用IApplicationThread对象thread调用了bindApplication,thread实际上就是ApplicationThreadProxy对象; AMS通过ApplicationThreadProxy对象与ActivityThread通信。所以去ApplicationThread中看bindApplication的真正实现

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n72" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public final void bindApplication(String processName, ApplicationInfo appInfo,

List<ProviderInfo> providers, ComponentName instrumentationName,

ProfilerInfo profilerInfo, Bundle instrumentationArgs,

IInstrumentationWatcher instrumentationWatcher,

IUiAutomationConnection instrumentationUiConnection, int debugMode,

boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,

Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,

Bundle coreSettings) {

if (services != null) {

// Setup the service cache in the ServiceManager

ServiceManager.initServiceCache(services);

}

setCoreSettings(coreSettings);

......

AppBindData data = new AppBindData();

data.processName = processName;

data.appInfo = appInfo;

data.providers = providers;

data.instrumentationName = instrumentationName;

data.instrumentationArgs = instrumentationArgs;

data.instrumentationWatcher = instrumentationWatcher;

data.instrumentationUiAutomationConnection = instrumentationUiConnection;

data.debugMode = debugMode;

data.enableOpenGlTrace = enableOpenGlTrace;

data.restrictedBackupMode = isRestrictedBackupMode;

data.persistent = persistent;

data.config = config;

data.compatInfo = compatInfo;

data.initProfilerInfo = profilerInfo;

sendMessage(H.BIND_APPLICATION, data);

}</pre>

这里又是用H发送了一个消息,是不是很像一个交通枢纽

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n74" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");

AppBindData data = (AppBindData)msg.obj;

handleBindApplication(data);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

</pre>

handleBindApplication内部就不分析了,Applcation对象的onCreate方法调用就是在这里面,它内部创建了Applcation对象

四、Activity周期如何执行

4.1、Activity的onCreate是怎么回调的

回到第二小节的startSpecificActivityLocked方法

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n79" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> 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.task.stack.setLaunchTime(r);

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.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);

}</pre>

在预启动之后,一般我们的应用进程就被孵化来了,直接执行realStartActivityLocked去启动Activity

在realStartActivityLocked内部调用了如下代码,现在你应该知道 app.thread是什么了

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n82" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,

System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),

new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,

task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,

newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);</pre>

直接到scheduleLaunchActivity真正实现,它的真正实现是在Applciation中的

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n84" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> 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);

}

</pre>

经过一堆的变量赋值之后,又通过H发送了一个消息LAUNCH_ACTIVITY,H在收到这个消息之后,执行下面

<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="java" cid="n86" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> 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);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n87" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {

// If we are getting ready to gc after going to the background, well

// we are back active so skip it.

unscheduleGcIdler();

mSomeActivitiesChanged = true;

if (r.profilerInfo != null) {

mProfiler.setProfiler(r.profilerInfo);

mProfiler.startProfiling();

}

// Make sure we are running with the most recent config.

handleConfigurationChanged(null, null);

if (localLOGV) Slog.v(

TAG, "Handling launch of " + r);

// Initialize before creating the activity

WindowManagerGlobal.initialize();

//一个 perform开头的方法,启动Activity

Activity a = performLaunchActivity(r, customIntent);

if (a != null) {

r.createdConfig = new Configuration(mConfiguration);

Bundle oldState = r.state;

//Launch

handleResumeActivity(r.token, false, r.isForward,

!r.activity.mFinished && !r.startsNotResumed);

if (!r.activity.mFinished && r.startsNotResumed) {

try {

r.activity.mCalled = false;

mInstrumentation.callActivityOnPause(r.activity);

if (r.isPreHoneycomb()) {

r.state = oldState;

}

if (!r.activity.mCalled) {

throw new SuperNotCalledException(

"Activity " + r.intent.getComponent().toShortString() +

" did not call through to super.onPause()");

}

} catch (SuperNotCalledException e) {

throw e;

} catch (Exception e) {

.....

}

r.paused = true;

}

.....

}

}</pre>

这个方法会将Activity创建出来

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n89" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

ActivityInfo aInfo = r.activityInfo;

r.activityInfo.targetActivity);

......

Activity activity = null;

try {

java.lang.ClassLoader cl = r.packageInfo.getClassLoader();

activity = mInstrumentation.newActivity(

cl, component.getClassName(), r.intent);

.......

} catch (Exception e) {

.......

}

Application app = r.packageInfo.makeApplication(false, mInstrumentation);

if (localLOGV) Slog.v(TAG, "Performing launch of " + r);

if (activity != null) {

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);

.......

//Activity的create方法执行

if (r.isPersistable()) {

mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);

} else {

mInstrumentation.callActivityOnCreate(activity, r.state);

}

.......

r.activity = activity;

r.stopped = true;

if (!r.activity.mFinished) {

//Activity的start方法执行

activity.performStart();

r.stopped = false;

}

mActivities.put(r.token, r);

return activity;

}</pre>

反射创建Activity,为啥要用反射呢,此处搞不清楚

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n91" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public Activity newActivity(ClassLoader cl, String className,

Intent intent)

throws InstantiationException, IllegalAccessException,

ClassNotFoundException {

return (Activity)cl.loadClass(className).newInstance();

}

</pre>

解析来mInstrumentation调用callActivityOnCreate方法

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n93" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public void callActivityOnCreate(Activity activity, Bundle icicle,

PersistableBundle persistentState) {

prePerformCreate(activity);

activity.performCreate(icicle, persistentState);

postPerformCreate(activity);

}</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n94" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> final void performCreate(Bundle icicle) {

onCreate(icicle);

mActivityTransitionState.readState(icicle);

performCreateCommon();

}</pre>

onCreate方法在此处被调用了。

4.2、Activity的onStart是怎么回调的

在performLaunchActivity中调用了callActivityOnCreate之后,又会调用 activity.performStart()

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n98" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> final void performStart() {

mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());

mFragments.noteStateNotSaved();

mCalled = false;

mFragments.execPendingActions();

mInstrumentation.callActivityOnStart(this);

if (!mCalled) {

throw new SuperNotCalledException(

"Activity " + mComponent.toShortString() +

" did not call through to super.onStart()");

}

mFragments.dispatchStart();

mFragments.reportLoaderStart();

mActivityTransitionState.enterReady(this);

}</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n99" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public void callActivityOnStart(Activity activity) {

activity.onStart();

}</pre>

到此处start方法又被调用了。

4.3、Activity的onResume是怎么回调的

handleLaunchActivity方法中,在调用performLaunchActivity之后,调用了handleResumeActivity方法。

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n103" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">ActivityThread.handleResumeActivity()

ActivityThread.handleResumeActivity()

Activity.performResume()

Instrumentation.callActivityOnResume();</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n104" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> public void callActivityOnResume(Activity activity) {

activity.mResumed = true;

activity.onResume();

if (mActivityMonitors != null) {

synchronized (mSync) {

final int N = mActivityMonitors.size();

for (int i=0; i<N; i++) {

final ActivityMonitor am = mActivityMonitors.get(i);

am.match(activity, activity, activity.getIntent());

}

}

}

}</pre>

到此Activity的onResume方法被调用,onPause方法已经讲解过,关于onStop,onDestory一样的套路分析。

五、总结

关于Activity的启动过程分析,三篇文章都分析完了

启动一个Activity的方式有多种,都是通过向Ams发送startActivity请求

Ams在启动Activity的时候,会判断目标进程有没有被创建,没有创建的话,向zygote进程发送创建进程的请求;

Zygote进程fork出新的子进程,即App进程;

App进程,通过Binder IPC向sytem_server进程发起attachApplication请求;

AMS所在的SystemServer进程在收到请求后,进行一系列准备工作后,再通过binder IPC向App进程发送scheduleLaunchActivity请求;

App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主线程发送LAUNCH_ACTIVITY消息;

主线程在收到Message后,通过发射机制创建目标Activity,并回调Activity.onCreate()等方法。

说明了一个Activity的启动流程, 重点在于把握Binder的通信原理,接着弄清楚APP进程,SystemServer进程,Zygote进程是怎么互相通信的

好了,文章基本上就到这里,Activity启动详细流程的分析就到此完毕了!,如有地方不对或者有不同理解的可以提出来

有需要文中完整代码的同学 可以 私信发送 “底层源码” 即可 免费获取

现在私信还可以获得 更多《Android 学习笔记+源码解析+面试视频》

最后我想说:

对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们

技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面

Android 架构师之路还很漫长,与君共勉

免责声明:本站所有信息均搜集自互联网,并不代表本站观点,本站不对其真实合法性负责。如有信息侵犯了您的权益,请告知,本站将立刻处理。联系QQ:1640731186
TAGS标签更多>>