前言:在之前的文章中已经写了apk的打包流程、安装流程,今天就是梳理一下apk系列的最后的流程--app启动流程。经过今天的梳理以后咱们就可以对apk包是怎么编译生成的、apk是怎么被安装到安卓手机的、用户点击了桌面icon以后app是怎么启动起来的 整个流程有清晰的认知和了解了。

下面先附上前面文章的传送门:

apk打包流程详解

apk安装流程详解

在开始分析app启动流程之前,我们先回想下平时是怎么启动一个App的:Android系统桌面->点击应用图标->启动App。

从这个过程来看,只要弄明白下面两个问题就可以解决我们“App如何被启动”的疑问。

在最开始先将apk启动涉及的“三个进程”,“六个大类”进行介绍一下:

  • Android系统桌面是什么?
  • 点击应用图标后Android系统执行了什么操作?

三个进程:

Launcher进程:整个App启动流程的起点,负责接收用户点击屏幕事件,它其实就是一个Activity,里面实现了点击事件,长按事件,触摸等事件,可以这么理解,把Launcher想象成一个总的Activity,屏幕上各种App的Icon就是这个Activity的button,当点击Icon时,会从Launcher跳转到其他页面。

SystemServer进程:这个进程在整个的Android进程中是非常重要的一个,地位和Zygote等同,它是属于Application Framework层的,Android中的所有服务,例如AMS, WindowsManager, PackageManagerService等等都是由这个SystemServer fork出来的。

App进程:你要启动的App所运行的进程。

六个大类:

ActivityManagerService:(AMS)AMS是Android中最核心的服务之一,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似,因此它在Android中非常重要,它本身也是一个Binder的实现类。

Instrumentation:监控应用程序和系统的交互。

ActivityThread:应用的入口类,通过调用main方法,开启消息循环队列。ActivityThread所在的线程被称为主线程。

ApplicationThread:ApplicationThread提供Binder通讯接口,AMS则通过代理调用此App进程的本地方法。

ActivityManagerProxy:AMS服务在当前进程的代理类,负责与AMS通信。

ApplicationThreadProxy:ApplicationThread在AMS服务中的代理类,负责与ApplicationThread通信。

可以说,启动的流程就是通过这六个大类在这三个进程之间不断通信的过程。

先搞清楚Android系统桌面是什么?

在Android系统中,Activity是视图存在的根本,那么我们可以通过命令 adb shell dumpsys activity activities 判断是哪个Activity为我们呈现桌面视图的。

以小米为例,通过USB连上电脑后,输入命令 adb shell dumpsys activity activities 得到结果如下:

在上图可以看到,显示桌面视图的Activity是com.miui.home包下的名为Launcher的Activity。

下面我copy了一张Launcher的这个Activity:

再来说说点击App图标后Android系统执行了什么操作?

既然Launcher是Activity,那就意味着我们点击桌面的事件可以表达为:呈现Android桌面视图(View)->点击View上某个应用图标->产生点击事件->点击事件被响应->通知Android系统的某个/某些进程->Android系统执行某些操作->启动App。

先看一下Launcher如何响应由我们产生的点击事件的:

/*** Launches the intent referred by the clicked shortcut.** @param v The view representing the clicked shortcut.*/
public void onClick(View v) {// Make sure that rogue clicks don't get through while allapps is launching, or after the// view has detached (it's possible for this to happen if the view is removed mid touch).if (v.getWindowToken() == null) {return;}if (!mWorkspace.isFinishedSwitchingState()) {return;}Object tag = v.getTag();if (tag instanceof ShortcutInfo) {// Open shortcutfinal Intent intent = ((ShortcutInfo) tag).intent;int[] pos = new int[2];v.getLocationOnScreen(pos);intent.setSourceBounds(new Rect(pos[0], pos[1],pos[0] + v.getWidth(), pos[1] + v.getHeight()));boolean success = startActivitySafely(v, intent, tag);if (success && v instanceof BubbleTextView) {mWaitingForResume = (BubbleTextView) v;mWaitingForResume.setStayPressed(true);}} else if (tag instanceof FolderInfo) {if (v instanceof FolderIcon) {FolderIcon fi = (FolderIcon) v;handleFolderClick(fi);}} else if (v == mAllAppsButton) {if (isAllAppsVisible()) {showWorkspace(true);} else {onClickAllAppsButton(v);}}
}
boolean startActivitySafely(View v, Intent intent, Object tag) {boolean success = false;try {success = startActivity(v, intent, tag);} catch (ActivityNotFoundException e) {Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);}return success;
}

从上面代码来看,产生点击事件后,如果产生点击事件的View的Tag是ShortcutInfo(即启动应用的快捷方式),就会取得ShortcutInfo中保存的Intent(这个Intent指向我们要启动的App),然后执行startActivitySafely(v, intent, tag)方法,而startActivitySafely方法只是对startActivity方法的简单封装。

所以,Launcher响应我们产生的点击事件后,实际上就是启动一个新的Activity。

我们现在回想下在App开发时,每个App都需要有一个“MainActivity”,这个Activity必须在AndroidManifest.xml文件中有以下配置:

<intent-filter>    <action android:name="android.intent.action.MAIN" />    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

在配置AndroidManifest.xml文件时,将Activity的Action指定为android.intent.action.MAIN,会使Activity在一个新的Task中启动(Task是一个Activity栈)。将category指定为android.intent.category.LAUNCHER,表示通过Intent启动此Activity时,只接受category为LAUNCHER的Intent。

所以,Launcher将会通过App的快捷方式(ShortcutInfo)得到应用的Intent,并通过这个Intent启动应用的“MainActivity”,从而启动应用。

到此我们研究的问题就从“App启动流程”变为“Activity启动流程”。

接下来我们就进入Launcher的startActivity方法里面探索“Activity启动流程”吧:在系统中其实Launcher是通过Binder通知ActivityManagerService启动Activity的。看下面的代码:

boolean startActivity(View v, Intent intent, Object tag) {intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);try {// Only launch using the new animation if the shortcut has not opted out (this is a// private contract between launcher and may be ignored in the future).boolean useLaunchAnimation = (v != null) &&!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);LauncherApps launcherApps = (LauncherApps)this.getSystemService(Context.LAUNCHER_APPS_SERVICE);if (useLaunchAnimation) {ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,v.getMeasuredWidth(), v.getMeasuredHeight());if (user == null || user.equals(android.os.Process.myUserHandle())) {// Could be launching some bookkeeping activitystartActivity(intent, opts.toBundle());} else {launcherApps.startMainActivity(intent.getComponent(), user,intent.getSourceBounds(),opts.toBundle());}} else {if (user == null || user.equals(android.os.Process.myUserHandle())) {startActivity(intent);} else {launcherApps.startMainActivity(intent.getComponent(), user,intent.getSourceBounds(), null);}}return true;} catch (SecurityException e) {Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();Log.e(TAG, "Launcher does not have the permission to launch " + intent +". Make sure to create a MAIN intent-filter for the corresponding activity " +"or use the exported attribute for this activity. "+ "tag="+ tag + " intent=" + intent, e);}return false;
}

在这个方法中,首先,将Intent的Flag设为Intent.FLAG_ACTIVITY_NEW_TASK,使得Android系统将创建一个新的Task来放置即将被打开的新Activity(应用的“MainActivity),然后获取一个布尔值以用于后续判断是否显示启动App的动画。

再然后获取Intent中是否传输了Parcelable格式的用户句柄,并通过Context.LAUNCHER_APPS_SERVICE获取用于在多用户情境下启动App的系统服务。

不管是否显示启动App的动画,最终都会执行startActivity(intent)或launcherApps.startMainActivity方法以启动应用的“MainActivity”。而launcherApps.startMainActivity只在用户句柄不为空且用户句柄不等于当前进程句柄时(其他用户的句柄)调用。

那为什么用户句柄会影响Activity的启动方式呢?

这一点和Android的多用户安全机制有关。

假设我们有用户A和用户B在使用同一台手机,用户A是无法访问到用户B的文件或者和用户B的App通信的。所以假如我们现在是用户A,但我们想启动用户B的App,是无法直接实现的,因为用户A没有权限访问到用户B的数据,即使我们在代码中强行把user id设为用户B的user id,交给内核执行时也会抛出SecurityException。因此我们需要取得用户A的句柄(和用户A相关的数据),将我们想启动的用户B的App的Intent、用户A的句柄交给内核,让拥有权限的Android系统服务(内核态进程)去访问用户B的数据并执行相关的操作。

假如是单用户情境,就会相对简单了。因为此时只有一个用户,而该用户始终有权限直接访问自己的数据。

接下来继续看startActivity(intent)如何启动Activity,进入Activity类后层层深入就可以看到最终调用的是startActivityForResult方法:

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {if (mParent == null) {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 {if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {// Note we want to go through this method for compatibility with// existing applications that may have overridden it.mParent.startActivityFromChild(this, intent, requestCode);}}
}

从代码上看,如果Launcher有mParent Activity,就会执行mParent.startActivityFromChild;如果没有,就会执行mInstrumentation.execStartActivity。进入mParent.startActivityFromChild方法会看到最终也是执行了mInstrumentation.execStartActivity。执行完成后,会取得一个ActivityResult对象,用于给调用者Activity传递一些数据,最后在Activity切换时显示Transition动画。

这里有一点需要指出的是:这里的ParentActivity指的是类似TabActivity、ActivityGroup关系的嵌套Activity。之所以要强调parent和child,是要避免混乱的Activity嵌套关系。

下面我们进入Instrumentation类看看execStartActivity方法:

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);}if (mActivityMonitors != null) {synchronized (mSync) {final int N = mActivityMonitors.size();for (int i=0; i<N; i++) {final ActivityMonitor am = mActivityMonitors.get(i);if (am.match(who, null, intent)) {am.mHits++;if (am.isBlocking()) {return requestCode >= 0 ? am.getResult() : null;}break;}}}}try {intent.migrateExtraStreamToClipData();intent.prepareToLeaveProcess();int result = ActivityManagerNative.getDefault().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;
}

首先,我们通过参数IBinder contextThread取得一个IApplicationThread类型的对象whoThread,而contextThread是由mMainThread.getApplicationThread()取得的ApplicationThread对象,此时mMainThread指的就是Launcher应用的主线程,所以whoThread指代的自然是Launcher的ApplicationThread。

因为Activity的onProvideReferrer()方法默认返回null,除非该方法被重写,而我们使用的Launcher并没有重写该方法,所以不用管referrer。

然后判断是否有ActivityMonitor,如果有,则即将要打开的Activity是否和ActivityMonitor中保存的IntentFilter匹配,如果匹配则增加ActivityMonitor的计数。大致是用于监控符合匹配规则的Activity的数量的。

最后调用ActivityManagerNative.getDefault().startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);启动Activity,并检查启动是否成功。

换句话说,最终负责启动Activity的是ActivityManager,前面得到的ApplicationThread也是在这里使用的。

那么ActivityManager、ApplicationThread、ActivityThread都是什么呢?接下来进行解答。

友情提示:在启动Activity的时候ActivityManagerService会通过Binder将Launcher切换到pause状态。

接着往下看,首先,调用ActivityManagerNative.getDefault()方法实际调用的是asInterface(IBinder obj)方法,也就意味着我们使用的其实是ActivityManagerProxy,而ActivityManagerProxy则是ActivityManagerService的代理,详见下面的代码:

static public IActivityManager getDefault() {return gDefault.get();}private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {protected IActivityManager create() {IBinder b = ServiceManager.getService("activity");if (false) {Log.v("ActivityManager", "default service binder = " + b);}IActivityManager am = asInterface(b);if (false) {Log.v("ActivityManager", "default service = " + am);}return am;}
};static public IActivityManager asInterface(IBinder obj) {if (obj == null) {return null;}IActivityManager in =(IActivityManager)obj.queryLocalInterface(descriptor);if (in != null) {return in;}return new ActivityManagerProxy(obj);
}

那么继续进入ActivityManagerProxy看:

class ActivityManagerProxy implements IActivityManager
{public ActivityManagerProxy(IBinder remote){mRemote = remote;}public IBinder asBinder(){return mRemote;}public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {// 创建两个Parcel对象,data用于传输启动Activity需要的数据,reply用于获取// 启动Activity操作执行后系统返回的响应Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);// caller 就是Launcher提供的ApplicationThread(也就是前面提到的whoThread)data.writeStrongBinder(caller != null ? caller.asBinder() : null);// 记录启动新Activity的应用的包名,也就是Launcher的包名data.writeString(callingPackage);intent.writeToParcel(data, 0);data.writeString(resolvedType);// 将resultTo这个IBinder对象写入data,实际写入的就是前面的参数——IBinder token// 而这个token是什么,我们暂时不管,后面会给出解释data.writeStrongBinder(resultTo);data.writeString(resultWho);data.writeInt(requestCode);data.writeInt(startFlags);if (profilerInfo != null) {data.writeInt(1);profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);} else {data.writeInt(0);}if (options != null) {data.writeInt(1);options.writeToParcel(data, 0);} else {data.writeInt(0);}mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);reply.readException();int result = reply.readInt();reply.recycle();data.recycle();return result;}
……省略余下代码……
}

将数据都写入后,就通过mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0)传输数据并得到响应(写入reply)。

前面已经提到了,ActivityManagerProxy是ActivityManagerService的代理,那么调用mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0)实际上就是通过Binder建立Launcher所在的进程与system_server进程(Android Framework层的服务几乎都由system_server进程管理,因此ActivityManagerService运行在system_server进程中)的通信,并把我们写入data的数据通过Binder传递给ActivityManagerService。

ActivityManagerService得到我们用Parcelable封装的data后就会调用startActivity方法为Launcher启动Activity:

@Override
public final int startActivity(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle options) {return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,resultWho, requestCode, startFlags, profilerInfo, options,UserHandle.getCallingUserId());
}@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {enforceNotIsolatedCaller("startActivity");userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,false, ALLOW_FULL_ONLY, "startActivity", null);// TODO: Switch to user app stacks here.return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,profilerInfo, null, null, options, false, userId, null, null);
}void enforceNotIsolatedCaller(String caller) {if (UserHandle.isIsolated(Binder.getCallingUid())) {throw new SecurityException("Isolated process not allowed to call " + caller);}
}

enforceNotIsolatedCaller("startActivity");作安全性检查,判断当前用户是否允许启动Activity,然后对之前传入的userId进行转换和安全性检查。最后调用mStackSupervisor.startActivityMayWait。这里的mStackSupervisor是ActivityStackSupervisor对象,前面提到过,Task是以堆栈形式组织Activity的集合,而Task又由ActivityStack管理,ActivityStackSupervisor则是管理ActivityStack的类。

源码太多,下面截取部分关键代码来说一下:

首先,通过下面代码段调用PackageManagerService解析Intent(我们想要打开的App的用于启动MainActivity的Intent),将解析的结果保存到ActivityInfo类型的对象里:

// Collect information about the target of the Intent.ActivityInfo aInfo =resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);// Method - resolveActivityActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,ProfilerInfo profilerInfo, int userId) {// Collect information about the target of the Intent.ActivityInfo aInfo;try {ResolveInfo rInfo =AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,PackageManager.MATCH_DEFAULT_ONLY| ActivityManagerService.STOCK_PM_FLAGS, userId);aInfo = rInfo != null ? rInfo.activityInfo : null;} catch (RemoteException e) {aInfo = null;}……省略,大致是做一些安全性检查和相关信息的设置……return aInfo;}

然后互斥锁锁住ActivityManagerService的实例mService,如果解析的ActivityInfo不为空,且ApplicationInfo有ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE标记,意味着调用者App是属于heavy-weight process,如果现在有另一个heavy-weight process正在运行,则需要进行一些额外的处理,然后进入到startActivityLocked方法。

这里通过注释我们可以发现,若App有ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE标记,App就可视为heavy-weight process,该标记可以在AndroidManifest.xml中设置,它是用于声明App是否享受系统提供的Activity状态保存/恢复功能的。但是似乎没有App能成为heavy-weight process,因为PackageParser的parseApplication方法并不会解析该标签。

之后在startActivityLocked方法中,得到Launcher(Activity)的ActivityRecord(Activity相关的信息),并创建我们要启动的Activity的ActivityRecord,最终执行startActivityUncheckedLocked继续启动Activity:

ActivityRecord sourceRecord = null;ActivityRecord resultRecord = null;if (resultTo != null) {sourceRecord = isInAnyStackLocked(resultTo);if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,"Will send result to " + resultTo + " " + sourceRecord);if (sourceRecord != null) {if (requestCode >= 0 && !sourceRecord.finishing) {resultRecord = sourceRecord;}}}…………ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,requestCode, componentSpecified, voiceSession != null, this, container, options);……err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,startFlags, true, options, inTask);

进入startActivityUncheckedLocked方法,完成一些简单的初始化后,向下执行到这段代码:如果Intent里有Intent.FLAG_ACTIVITY_NEW_DOCUMENT标记(在AndroidManifest.xml中声明),且即将要打开的Activity的启动模式又被声明为SingleInstance或SingleTask,那么Intent中携带的标记和AndroidManifest中声明的标记出现冲突,而AndroidManifest的优先级是高于Intent的,因此将launchFlags的对应位置为0。

然后是对launchFlags一系列的置位,目的是设置启动模式。

if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&(launchSingleInstance || launchSingleTask)) {// We have a conflict between the Intent and the Activity manifest, manifest wins.Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +"\"singleInstance\" or \"singleTask\"");launchFlags &=~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);} else {switch (r.info.documentLaunchMode) {case ActivityInfo.DOCUMENT_LAUNCH_NONE:break;case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;break;case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;break;case ActivityInfo.DOCUMENT_LAUNCH_NEVER:launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;break;}}
}
……if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}// If we are actually going to launch in to a new task, there are some cases where
// we further want to do multiple task.
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {if (launchTaskBehind|| r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {launchFlags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;}
}……if (inTask == null) {if (sourceRecord == null) {// This activity is not being started from another...  in this// case we -always- start a new task.if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {Slog.w(TAG, "startActivity called from non-Activity context; forcing " +"Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;}} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {// The original activity who is starting us is running as a single// instance...  this new activity it is starting must go on its// own task.launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;} else if (launchSingleInstance || launchSingleTask) {// The activity being started is a single instance...  it always// gets launched into its own task.launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;}
}……// 因为我们是从Launcher启动目的Activity,所以sourceRecord不为null,值为Launcher的ActivityRecord
if (sourceRecord != null) {if (sourceRecord.finishing) {// 如果sourceRecord表示的Activity正在结束/被销毁,那么我们不能把该Activity看作启动目的// Activity的源Activity,因为和源Activity关联的Task现在可能是空的(没有Activity)或者// 也在结束/被销毁的过程中,所以我们不能盲目地把目的Activity放到该Task中。取而代之的是,// 我们会为它找到一个可用的Task,但我们要先保存源Activity的Task的信息,使得我们在创建新// 的可用的Task时能用到里面的一些信息。if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {Slog.w(TAG, "startActivity called from finishing " + sourceRecord+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;newTaskInfo = sourceRecord.info;newTaskIntent = sourceRecord.task.intent;}sourceRecord = null;sourceStack = null;} else {sourceStack = sourceRecord.task.stack;}
} else {sourceStack = null;
}……// 为目的Activity创建新的Task
if (r.resultTo == null && inTask == null && !addingToTask&& (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {newTask = true;targetStack = computeStackFocus(r, newTask);targetStack.moveToFront("startingNewTask");if (reuseTask == null) {r.setTask(targetStack.createTaskRecord(getNextTaskId(),newTaskInfo != null ? newTaskInfo : r.info,newTaskIntent != null ? newTaskIntent : intent,voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),taskToAffiliate);if (DEBUG_TASKS) Slog.v(TAG_TASKS,"Starting new activity " + r + " in new task " + r.task);} else {r.setTask(reuseTask, taskToAffiliate);}if (isLockTaskModeViolation(r.task)) {Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;}if (!movedHome) {if ((launchFlags &(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {// Caller wants to appear on home activity, so before starting// their own activity we will bring home to the front.r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);}}
}

完成上面一系列的处理后,调用ActivityStack的startActivityLocked方法继续执行启动Activity需要的操作,targetStack是通过这行代码targetStack = computeStackFocus(r, newTask)为用户新建的ActivityStack:

mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,intent, r.getUriPermissionsLocked(), r.userId);if (sourceRecord != null && sourceRecord.isRecentsActivity()) {r.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
}
if (newTask) {EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
}
ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
targetStack.mLastPausedActivity = null;
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
if (!launchTaskBehind) {// Don't set focus on an activity that's going to the back.mService.setFocusedActivityLocked(r, "startedActivity");
}
return ActivityManager.START_SUCCESS;

进入到ActivityStack的startActivityLocked方法,首先为目的Activity创建ProcessRecord,然后用WindowManager进行一些切换窗口的操作,最后调用mStackSupervisor.resumeTopActivitiesLocked(this, r, options):

if (!isHomeStack() || numActivities() > 0) {// We want to show the starting preview window if we are// switching to a new task, or the next activity's process is// not currently running.boolean showStartingIcon = newTask;ProcessRecord proc = r.app;if (proc == null) {proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);}if (proc == null || proc.thread == null) {showStartingIcon = true;}……调用WindowManager切换窗口……
}……if (doResume) {mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
}

进入到resumeTopActivitiesLocked方法,调用resumeTopActivityLocked方法将所有ActivityStack(多个显示设备,每个设备对应一个ActivityStack)栈顶的Activity切换到resume状态(生命周期的onResume),而resumeTopActivityLocked方法先避免递归调用,然后调用ActivityStack的resumeTopActivityInnerLocked方法:

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,Bundle targetOptions) {if (targetStack == null) {targetStack = mFocusedStack;}// Do targetStack first.boolean result = false;if (isFrontStack(targetStack)) {result = targetStack.resumeTopActivityLocked(target, targetOptions);}for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {final ActivityStack stack = stacks.get(stackNdx);if (stack == targetStack) {// Already started above.continue;}if (isFrontStack(stack)) {stack.resumeTopActivityLocked(null);}}}return result;
}

下面resumeTopActivityInnerLocked()这段代码主要就是做一些前期的检查,避免做多余的工作浪费时间,并且确保目标Activity处于正确的“状态”,使得我们后面能把它切换到resume状态并显示:

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {// 判断ActivityManagerService是否已经启动完毕if (!mService.mBooting && !mService.mBooted) {// Not ready yet!return false;}// 获取parentActivity,如果parentActivity还未处于resume状态,则不能将stack栈顶的Activity切换为resume状态(Activity的嵌套关系不能弄乱)ActivityRecord parent = mActivityContainer.mParentActivity;if ((parent != null && parent.state != ActivityState.RESUMED) ||!mActivityContainer.isAttachedLocked()) {// Do not resume this stack if its parent is not resumed.// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.return false;}// 如果有正在初始化的Activity没有位于ActivityStack的栈顶,且正在执行window的启动和显示,// 则要将window相关的操作取消。因为这类Activity的窗口有可能被孤立,那么它们有可能永远也不会进入resume状态cancelInitializingActivities();// 取得当前ActivityStack栈顶Activity的ActivityRecordfinal ActivityRecord next = topRunningActivityLocked(null);// 记住我们怎样处理pause/resume状态切换,并确保无论何时结束处理都会重置状态final boolean userLeaving = mStackSupervisor.mUserLeaving;mStackSupervisor.mUserLeaving = false;final TaskRecord prevTask = prev != null ? prev.task : null;if (next == null) {// next为null表示当前ActivityStack没有要显示的Activityfinal String reason = "noMoreActivities";if (!mFullscreen) {// 如果当前ActivityStack不是全屏的,将焦点切换到下一个拥有Activity的可见ActivityStack中final ActivityStack stack = getNextVisibleStackLocked();if (adjustFocusToNextVisibleStackLocked(stack, reason)) {return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);}}// 如果ActivityStack是全屏的,却没有可以显示的Activity,那么就显示桌面(Launcher)ActivityOptions.abort(options);if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: No more activities go home");if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();return isOnHomeDisplay() &&mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);}next.delayedResume = false;// 如果当前栈顶Activity处于resume状态,且就是我们要打开的Activity,则直接结束if (mResumedActivity == next && next.state == ActivityState.RESUMED &&mStackSupervisor.allResumedActivitiesComplete()) {// Make sure we have executed any pending transitions, since there// should be nothing left to do at this point.mWindowManager.executeAppTransition();mNoAnimActivities.clear();ActivityOptions.abort(options);if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Top activity resumed " + next);if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();return false;}// 对prevActivity(Launcher)所在的Task进行一些判断,如果prevTask和nextTask相同,那么直接将// prevTask直接设为栈顶Task;如果prevTask不是当前ActivityStack栈顶的Task,那么它后面的Task// 都应该放到Launcher的Task后面;后面则是有关是否为桌面的判断和处理了。final TaskRecord nextTask = next.task;if (prevTask != null && prevTask.stack == this &&prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();if (prevTask == nextTask) {prevTask.setFrontOfTask();} else if (prevTask != topTask()) {// This task is going away but it was supposed to return to the home stack.// Now the task above it has to return to the home task instead.final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE);} else if (!isOnHomeDisplay()) {return false;} else if (!isHomeStack()){if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Launching home next");final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();return isOnHomeDisplay() &&mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "prevFinished");}}// 如果ActivityManagerService处于休眠状态,而且此时没有Activity处于resume状态// 且栈顶Activity处于pause状态,则中断调度if (mService.isSleepingOrShuttingDown()&& mLastPausedActivity == next&& mStackSupervisor.allPausedActivitiesComplete()) {// Make sure we have executed any pending transitions, since there// should be nothing left to do at this point.mWindowManager.executeAppTransition();mNoAnimActivities.clear();ActivityOptions.abort(options);if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Going to sleep and all paused");if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();return false;}// Make sure that the user who owns this activity is started.  If not,// we will just leave it as is because someone should be bringing// another user's activities to the top of the stack.if (mService.mStartedUsers.get(next.userId) == null) {Slog.w(TAG, "Skipping resume of top activity " + next+ ": user " + next.userId + " is stopped");if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();return false;}// 确保我们要启动的Activity没有处于stop队列、休眠队列、等待变为可见队列中mStackSupervisor.mStoppingActivities.remove(next);mStackSupervisor.mGoingToSleepActivities.remove(next);next.sleeping = false;mStackSupervisor.mWaitingVisibleActivities.remove(next);if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);// If we are currently pausing an activity, then don't do anything// until that is done.if (!mStackSupervisor.allPausedActivitiesComplete()) {if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,"resumeTopActivityLocked: Skip resume: some activity pausing.");if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();return false;}……待续……
}

紧接上面的代码在后续的工作就是:将Launcher切换到pause状态,用WindowManager将Launcher的窗口隐藏。

现在只完成了Activity相关的预处理工作,目标应用的进程和主线程还没有创建,因此后面会进入if的false分支调用mStackSupervisor.startSpecificActivityLocked方法创建应用进程;如果目标Activity的进程和主线程已经创建,则进入if语句的true分支直接将目标Activity切换到resume状态,并显示目标Activity的窗口。此流程看下面的代码:(上面的代码后续)

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {……续上……// 步入setLaunchSource方法后可以知道,该方法实际是通过PowerManager的setWorkSource方法// 设置WakeLock,使得在执行后面的工作时系统不会进入休眠状态mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);// 现在开始将当前Activity切换到pause状态,使得栈顶Activity可以切换到resume状态boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;// 将后台ActivityStack的Activity切换到pause状态boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);// 将当前ActivityStack中正在显示Activity切换到pause状态if (mResumedActivity != null) {if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Pausing " + mResumedActivity);pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);}if (pausing) {if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,"resumeTopActivityLocked: Skip resume: need to start pausing");// At this point we want to put the upcoming activity's process// at the top of the LRU list, since we know we will be needing it// very soon and it would be a waste to let it get killed if it// happens to be sitting towards the end.if (next.app != null && next.app.thread != null) {mService.updateLruProcessLocked(next.app, true, null);}if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();return true;}……ActivityStack lastStack = mStackSupervisor.getLastStack();if (next.app != null && next.app.thread != null) {if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next);// 目标Activity已经可见mWindowManager.setAppVisibility(next.appToken, true);next.startLaunchTickingLocked();ActivityRecord lastResumedActivity =lastStack == null ? null :lastStack.mResumedActivity;ActivityState lastState = next.state;mService.updateCpuStats();// 目标Activity切换到resume状态if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next + " (in existing)");next.state = ActivityState.RESUMED;mResumedActivity = next;next.task.touchActiveTime();mRecentTasks.addLocked(next.task);mService.updateLruProcessLocked(next.app, true, null);updateLRUListLocked(next);mService.updateOomAdjLocked();……mStackSupervisor.startSpecificActivityLocked(next, true, true);}
……
}

接下来ActivityManagerService就要为即将打开的应用创建进程。

进入ActivityStackSupervisor类的startSpecificActivityLocked方法,首先通过应用的包名和uid取得ProcessRecord,判断ProcessRecord是否被创建,若创建,则直接启动Activity;否则调用ActivityManagerService的startProcessLocked方法创建应用进程:

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

进入到ActivityManagerService的startProcessLocked方法,首先判断要创建的进程是否为隔离进程(isolated),由于不是隔离进程,则直接进入true分支,然后再次获取ProcessRecord。如果Intent有FLAG_FROM_BACKGROUND标记,则在后台启动badProcess;否则清空进程的崩溃次数,并将进程移出badProcess集合(如果进程存在的话)。然后调用newProcessRecordLocked方法创建ProcessRecord,最后再调用另一个重载的startProcessLocked方法创建进程:

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {long startTime = SystemClock.elapsedRealtime();ProcessRecord app;if (!isolated) {app = getProcessRecordLocked(processName, info.uid, keepIfLarge);checkTime(startTime, "startProcess: after getProcessRecord");if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {// If we are in the background, then check to see if this process// is bad.  If so, we will just silently fail.if (mBadProcesses.get(info.processName, info.uid) != null) {if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid+ "/" + info.processName);return null;}} else {// When the user is explicitly starting a process, then clear its// crash count so that we won't make it bad until they see at// least one crash dialog again, and make the process good again// if it had been bad.if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid+ "/" + info.processName);mProcessCrashTimes.remove(info.processName, info.uid);if (mBadProcesses.get(info.processName, info.uid) != null) {EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,UserHandle.getUserId(info.uid), info.uid,info.processName);mBadProcesses.remove(info.processName, info.uid);if (app != null) {app.bad = false;}}}} else {// If this is an isolated process, it can't re-use an existing process.app = null;}……String hostingNameStr = hostingName != null? hostingName.flattenToShortString() : null;if (app == null) {checkTime(startTime, "startProcess: creating new process record");app = newProcessRecordLocked(info, processName, isolated, isolatedUid);if (app == null) {Slog.w(TAG, "Failed making new process record for "+ processName + "/" + info.uid + " isolated=" + isolated);return null;}app.crashHandler = crashHandler;checkTime(startTime, "startProcess: done creating new process record");} else {// If this is a new package in the process, add the package to the listapp.addPackage(info.packageName, info.versionCode, mProcessStats);checkTime(startTime, "startProcess: added package to existing proc");}// 如果系统还没启动完毕,则等待系统启动完毕后再启动进程if (!mProcessesReady&& !isAllowedWhileBooting(info)&& !allowWhileBooting) {if (!mProcessesOnHold.contains(app)) {mProcessesOnHold.add(app);}if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,"System not ready, putting on hold: " + app);checkTime(startTime, "startProcess: returning with proc on hold");return app;}checkTime(startTime, "startProcess: stepping in to startProcess");startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);checkTime(startTime, "startProcess: done starting proc!");return (app.pid != 0) ? app : null;
}

调用newProcessRecordLocked方法根据ApplicationInfo创建ProcessRecord,并让ActivityManagerService管理该ProcessRecord,过程比较简单就不贴代码了,直接看startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs)方法。

进入startProcessLocked方法,首先将app的pid初始化,若进程已经存在(pid不等于0),则先清除超时信息,再讲pid置为0,然后确保app不在mProcessesOnHold列表中。

mProcessesOnHold代表在系统启动完毕前尝试启动的进程,这部分进程会先在该列表中待着,等到系统启动完毕再启动。

完成一系列的初始化操作后,调用Process.start方法创建应用进程,然后以进程pid为key,app(ProcessRecord)为value存储到ActivityManagerService的mPidsSelfLocked中。

Process.start方法创建应用进程是通过Zygote进程完成的,设置好参数和创建选项后通过zygoteState.writer将数据交给Zygote进程,它会调用fork()创建进程。

在这里要注意一个地方,我们通过if (entryPoint == null) entryPoint = "android.app.ActivityThread"这行代码设置了进程创建完成后的入口点(Process.start的参数注释),因此Zygote进程完成了进程创建的操作后就会执行ActivityThread的main()方法。

下面看startProcessLocked的代码:

private final void startProcessLocked(ProcessRecord app, String hostingType,String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {long startTime = SystemClock.elapsedRealtime();if (app.pid > 0 && app.pid != MY_PID) {checkTime(startTime, "startProcess: removing from pids map");synchronized (mPidsSelfLocked) {mPidsSelfLocked.remove(app.pid);mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);}checkTime(startTime, "startProcess: done removing from pids map");app.setPid(0);}if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,"startProcessLocked removing on hold: " + app);mProcessesOnHold.remove(app);
……// Start the process.  It will either succeed and return a result containing// the PID of the new process, or else throw a RuntimeException.boolean isActivityProcess = (entryPoint == null);if (entryPoint == null) entryPoint = "android.app.ActivityThread";Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +app.processName);checkTime(startTime, "startProcess: asking zygote to start proc");Process.ProcessStartResult startResult = Process.start(entryPoint,app.processName, uid, uid, gids, debugFlags, mountExternal,app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,app.info.dataDir, entryPointArgs);
……
}

进入到ActivityThread的main方法以后,首先进行一些初始化(包括参数设置、性能安全监控之类的),然后初始化Looper(Looper、Handler消息机制),创建ActivityThread,存储线程的Handler,最后启动Looper监听消息。

再之后ActivityThread通过Binder将ApplicationThread对象传递给ActivityManagerService,并完成启动Activity的后续工作。

到这里ActivityThread的初始化就完成了,但是回想一下前面的工作,我们现在将Launcher切换到了pause状态,但由于目标应用进程和线程还没有创建,所以我们还没有把目标应用的MainActivity切换到resume状态。所以就意味着,我们还需要进行应用进程和ActivityManagerService所在的system_server进程的通信,告诉ActivityManagerService我们已经创建好了进程和线程,接下来把MainActivity状态切换到resume中,就能打开应用了。

这一步工作在哪里完成的呢:thread.attach(false)

final IActivityManager mgr = ActivityManagerNative.getDefault();看到这行代码有没有熟悉的感觉?前面我们就通过ActivityManagerNative.getDefault()取得ActivityManagerService的代理对象,完成了启动MainActivity的前期工作。这里再次取得代理对象,并调用了ActivityManagerService的attachApplication方法。

public static void main(String[] args) {
……Process.setArgV0("<pre-initialized>");Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false);if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");
}private void attach(boolean system) {sCurrentActivityThread = this;mSystemThread = system;if (!system) {ViewRootImpl.addFirstDrawHandler(new Runnable() {@Overridepublic void run() {ensureJitEnabled();}});android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",UserHandle.myUserId());RuntimeInit.setApplicationObject(mAppThread.asBinder());final IActivityManager mgr = ActivityManagerNative.getDefault();try {mgr.attachApplication(mAppThread);} catch (RemoteException ex) {// Ignore}
……} else {
……}
……
}

进入到ActivityManagerService的attachApplication方法,前面我们已经存储过目标应用的pid-ProcessRecord键值对了,因此这里的app不为null。然后向下执行,激活ProcessRecord并将ProcessRecord绑定到应用进程。然后通过Binder(thread.bindApplication)将各种应用相关信息传递给应用进程,进行应用进程一些必要的设置。最后调用mStackSupervisor.attachApplicationLocked(app)方法将ApplicationThread对象传递给ActivityManagerService方便后续应用进程与ActivityManagerService的通信(如:将MainActivity切换到resume状态),并完成启动应用的所有工作。

@Override
public final void attachApplication(IApplicationThread thread) {synchronized (this) {int callingPid = Binder.getCallingPid();final long origId = Binder.clearCallingIdentity();attachApplicationLocked(thread, callingPid);Binder.restoreCallingIdentity(origId);}
}private final boolean attachApplicationLocked(IApplicationThread thread,int pid) {// Find the application record that is being attached...  either via// the pid if we are running in multiple processes, or just pull the// next app record if we are emulating process with anonymous threads.ProcessRecord app;if (pid != MY_PID && pid >= 0) {synchronized (mPidsSelfLocked) {app = mPidsSelfLocked.get(pid);}} else {app = null;}// 此时app不为null,跳过if (app == null) {
……}// 清除ProcessRecord中的信息,以确保没有不相关进程的信息if (app.thread != null) {handleAppDiedLocked(app, true, true);}// Tell the process all about itself.if (DEBUG_ALL) Slog.v(TAG, "Binding process pid " + pid + " to record " + app);// 注册DeathRecipient,确保应用意外关闭时系统进程能收到通知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);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;mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
……// 调用ActivityThread的bindApplication方法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) {
……}……// 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;}}// Find any services that should be running in this process...if (!badApp) {
……}// Check if a next-broadcast receiver is in this process...if (!badApp && isPendingBroadcastProcessLocked(pid)) {
……}// Check whether the next backup agent is in this process...if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
……}……return true;
}

后面就是ActivityManagerService通知ActivityThread启动Activity了。

回到ActivityThread,先看bindApplication方法,就是将上面传的数据存储在AppBindData中,然后通过Message、Handler发送出去,我们再看看Handler是怎么处理H.BIND_APPLICATION类型的Message的。

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) {
……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);
}
case BIND_APPLICATION:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");AppBindData data = (AppBindData)msg.obj;handleBindApplication(data);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;

可以看到最终调用了handleBindApplication方法,进入到handleBindApplication方法,首先进行一些初始化操作,然后取出data中存储的进程名,为应用进程设置进程名。然后创建应用的Context,也就是应用的运行上下文,通过Context我们可以访问到应用相关的各种资源文件(图片、布局文件等等)。然后创建进程的Instrumentation对象、Application对象,装载Provider,最终调用mInstrumentation.callApplicationOnCreate(app)方法,也就是调用我们开发App时,Application类(或子类)的onCreate()方法。

private void handleBindApplication(AppBindData data) {
……// send up app name; do this *before* waiting for debuggerProcess.setArgV0(data.processName);android.ddm.DdmHandleAppName.setAppName(data.processName,UserHandle.myUserId());……设置进程运行信息……final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);……继续进程的初始化……if (data.instrumentationName != null) {……} else {mInstrumentation = new Instrumentation();}……try {// If the app is being launched for full backup or restore, bring it up in// a restricted environment with the base application class.Application app = data.info.makeApplication(data.restrictedBackupMode, null);mInitialApplication = app;// don't bring up providers in restricted mode; they may depend on the// app's custom Application classif (!data.restrictedBackupMode) {List<ProviderInfo> providers = data.providers;if (providers != null) {installContentProviders(app, providers);// For process that contains content providers, we want to// ensure that the JIT is enabled "at some point".mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);}}……try {mInstrumentation.callApplicationOnCreate(app);} catch (Exception e) {if (!mInstrumentation.onException(app, e)) {throw new RuntimeException("Unable to create application " + app.getClass().getName()+ ": " + e.toString(), e);}}} finally {StrictMode.setThreadPolicy(savedPolicy);}
}

至此应用进程相关的初始化和相关的设置就完成了,接下来只要切换MainActivity的状态就大功告成了。

进入到ActivityStackSupervisor类的attachApplicationLocked方法,该方法遍历mActivityDisplays列表得到当前所有ActivityStack,然后取得前台ActivityStack栈顶的ActivityRecord,不为空则启动该对该ActivityRecord调用realStartActivityLocked方法。

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {final String processName = app.processName;boolean didSomething = false;for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {final ActivityStack stack = stacks.get(stackNdx);if (!isFrontStack(stack)) {continue;}ActivityRecord hr = stack.topRunningActivityLocked(null);if (hr != null) {if (hr.app == null && app.uid == hr.info.applicationInfo.uid&& processName.equals(hr.processName)) {try {if (realStartActivityLocked(hr, app, true, true)) {didSomething = true;}} catch (RemoteException e) {Slog.w(TAG, "Exception in new application when starting activity "+ hr.intent.getComponent().flattenToShortString(), e);throw e;}}}}}if (!didSomething) {ensureActivitiesVisibleLocked(null, 0);}return didSomething;
}

到这里,后面就该ActivityThread调度执行Activity生命周期方法,完成Activity的启动。

进入到realStartActivityLocked方法,进行一些前期处理后调用ActivityThread的scheduleLaunchActivity方法,将创建ActivityClientRecord存储我们传入的各种应用相关的数据,通过Handler机制发送。当Handler接收到LAUNCH_ACTIVITY类型的消息时,执行handleLaunchActivity方法。

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);@Override
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);
}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);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;

进入到handleLaunchActivity方法,首先进行参数设置,然后调用performLaunchActivity方法得到目标应用的MainActivity并使其分别调用onCreate、onStart方法,然后调用handleResumeActivity方法让MainActivity进入resume状态,完成启动。

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
……Activity a = performLaunchActivity(r, customIntent);if (a != null) {r.createdConfig = new Configuration(mConfiguration);Bundle oldState = r.state;handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed);……} else {
……}
}private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {// 初始化设置
……// 通过反射获得MainActivityActivity activity = null;try {java.lang.ClassLoader cl = r.packageInfo.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);r.intent.prepareToEnterProcess();if (r.state != null) {r.state.setClassLoader(cl);}} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to instantiate activity " + component+ ": " + e.toString(), e);}}try {
……if (activity != null) {// 为MainActivity创建运行的上下文环境Context,并与Activity绑定Context appContext = createBaseContextForActivity(r, activity);CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config = new Configuration(mCompatConfiguration);if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);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);……// 回调MainActivity生命周期的onCreate方法if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}
……// 回调MainActivity生命周期的onStart方法if (!r.activity.mFinished) {activity.performStart();r.stopped = false;}
……} 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;
}final void handleResumeActivity(IBinder token,boolean clearHide, boolean isForward, boolean reallyResume) {// If we are getting ready to gc after going to the background, well// we are back active so skip it.unscheduleGcIdler();mSomeActivitiesChanged = true;// TODO Push resumeArgs into the activity for considerationActivityClientRecord r = performResumeActivity(token, clearHide);……
}

好了,到了这里,apk启动流程的源码分析就算是完成了,咱们已经对apk的启动流程有清晰的认知和理解了。

最后总结一下app启动步骤:

(1)启动的起点发生在Launcher活动中,启动一个app说简单点就是启动一个Activity,那么我们说过所有组件的启动,切换,调度都由AMS来负责的,所以第一步就是Launcher响应了用户的点击事件,然后通知AMS;

(2)AMS得到Launcher的通知,就需要响应这个通知,主要就是新建一个Task去准备启动Activity,并且告诉Launcher你可以休息了(Paused);

(3)Launcher得到AMS让自己“休息”的消息,那么就直接挂起,并告诉AMS我已经Paused了;

(4)AMS知道了Launcher已经挂起之后,就可以放心的为新的Activity准备启动工作了,首先,APP肯定需要一个新的进程去进行运行,所以需要创建一个新进程,这个过程是需要Zygote参与的,AMS通过Socket去和Zygote协商,如果需要创建进程,那么就会fork自身,创建一个线程,新的进程会导入ActivityThread类,这就是每一个应用程序都有一个ActivityThread与之对应的原因;

(5)进程创建好了,通过调用上述的ActivityThread的main方法,这是应用程序的入口,在这里开启消息循环队列,这也是主线程默认绑定Looper的原因;

(6)这时候,App还没有启动完,要永远记住,四大组建的启动都需要AMS去启动,将上述的应用进程信息注册到AMS中,AMS再在堆栈顶部取得要启动的Activity,通过一系列链式调用去完成App启动;
最后copy这张图很好的描述了上面的六大步:

好了,本文结束了  see  you

Android App启动流程详解相关推荐

  1. android zygote启动流程,Android zygote启动流程详解

    对zygote的理解 在Android系统中,zygote是一个native进程,是所有应用进程的父进程.而zygote则是Linux系统用户空间的第一个进程--init进程,通过fork的方式创建并 ...

  2. 【线上沙龙直播报名】App 启动流程详解及其优化

    点击上方"公众号"可以订阅哦 [美团点评技术沙龙Online]是美团点评技术团队推出的线上分享课程,每月2-3期,采用目前最火热的线上直播形式,邀请美团点评技术专家,面向互联网技术 ...

  3. U-Boot启动流程详解

    参考:U-Boot顶层目录链接脚本文件(u-boot.lds)介绍 作者:一只青木呀 发布时间: 2020-10-23 13:52:23 网址:https://blog.csdn.net/weixin ...

  4. iOS APP上架流程详解

    iOS APP上架流程详解 青葱烈马 2016.04.28  前言:作为一名 iOS 开发工程师, APP 的上架是必备技能. iOS 上架的流程主要可以简单总结为: 一个包,两个网址,三个证书, 一 ...

  5. 【Autosar 启动流程详解】

    Autosar 启动流程详解 1. vLinkGen_Template.lsl 2. BrsHwStartup.c 3.BrsMainStartup.c 4.BrsMain.c 链接文件: 1. vL ...

  6. 【正点原子Linux连载】第三十二章 U-Boot启动流程详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  7. golang程序启动流程详解

    golang程序启动流程详解 环境 go1.16.5 linux/amd64 用例 package mainimport "fmt"func main() {fmt.Println ...

  8. 苹果app开发流程详解​

    苹果App Store上传应用流程详解,在向AppStore提交应用之前,开发者首先要成为苹果iOS开发者项目的成员,每年向苹果缴纳99美元或199美元的费用(具体申请方法后期更新).​ 免688开发 ...

  9. Springboot启动流程详解

    SpringMVC请求流程详解 SpringMVC框架是一个基于请求驱动的Web框架,并且使用了'前端控制器'模型来进行设计,再根据'请求映射规则'分发给相应的页面控制器进行处理. (一)整体流程 每 ...

最新文章

  1. 贴吧html标签,html标签3(转载)
  2. C/C++中链接属性
  3. Python 学习笔记 - socket(基本原理和流程)
  4. UA OPTI501 电磁波8 麦克斯韦方程边界条件的推导
  5. postman 变量
  6. Node.js Stream - 基础篇
  7. hystrix合并请求_Hystrix中的批处理(折叠)请求
  8. Linux shell重复执行某命令n次
  9. 数据结构 多路查找树 ---------B树和B+树的简单介绍
  10. 下载OneDrive共享的数据集
  11. Python技术、爬虫、数据分析问题汇总【自用】
  12. 金三银四大厂面经总结,淘汰了80%的Java面试者
  13. MemcacheQ 安装与使用
  14. mqtt server python_Python使用mqtt极简例子
  15. Qt绘制中国地图轮廓边界
  16. 74LS165芯片单颗与级联的万能代码|2021-10-6
  17. 解决 PHP http_build_query() 预期得到 not 却得到 ¬ 的问题
  18. Exp3 免杀原理与实践 20164323段钊阳
  19. 学习编程前需要知道什么?
  20. 制作 docker 精简 jre8 基础镜像

热门文章

  1. R语言用WinBUGS 软件对学术能力测验(SAT)建立层次(分层)贝叶斯模型
  2. 指纹识别的原理与优势
  3. [转]Cloudera Manager和CDH5.8离线安装
  4. UE开机入网流程及RRC连接建立
  5. WIN10系统设置默认文件查看方式
  6. 认沽期权长短仓应用法
  7. Windows下用Python获取电脑显示器物理尺寸和PPI
  8. 概率相关图像的绘制_正态分布_uniform_pearson
  9. JAVA NIO实现客户端与服务端通信
  10. selenium 自动化测试工具(二)常用定位方式