探究 Android Application 的启动流程

文章目录
  1. 1. 关于 Application
  2. 2. Application 的启动流程
  3. 3. 总结
  4. 4. 参考文献

Fear is not real, why so serious?

平时,我们点击手机主页上的一个 App 图标,就能正常地启动一个 App 应用。站在用户的角度,这个过程没什么特殊的。但是,从开发者的角度,其背后或许暗藏着一些玄机。本期,就来着重地分析下,探究启动一个 App 走过的流程。

关于 Application

Android Application 与其他移动平台相比,有着两个重要的不同点:

  • 每一个 Android Application 都运行在一个独立的空间里,其运行在一个单独的进程中,有着自己特定的虚拟机,系统分配给其一个唯一的 user ID;
  • Android Application 并没有一个类似 Java 程序中程序入口的 main() 方法,其由我们所熟知的四大组件构成,此类组件可以启动其他 Application 的组件。

Android 中,每一个 Application 都被设计成为单独的进程,Application 可以根据自己的需要,来决定是否需要启用多个进程。总的来说,此 Application 与其他的 Application 和系统服务是相互独立的。细想一下,为了达成有效的解耦和系统的稳定性,不因某个应用程序的崩溃就影响到其他应用进程或者系统服务进程,Application 着实须运行在不同的进程上。

Application 的进程与 Android 系统中其他的守护进程不同,内存不够时,某些应用进程或许会被系统回收掉,应用进程也是有着自己的生命周期的,更多参见官网Processes and Threads。然而,要注意的是,Android 应用组件不一定要运行在单独的进程上,其可以运行在多个进程中,如对 Android 某个组件指定运行的进程android:process,即可让其运行在其他进程中。

事实上,每个 Application 的进程都相当于一个沙箱,而每个 Application 就像一个 User,只能对其目录下的内容具有访问和读写权限,从根源上保护了其他应用程序,如下图所示:

Application 的启动流程

探究整个启动流程之前,先谈一下 ActivityManager 的整体架构。

I. ActivityManager 的整体架构

开发中,会涉及许多 Activity 之间的跳转,在 Launcher 中,点击 App 图标跳转同理,都会调用到context.startActivity(intent)方法。其中,Launcher 在一个进程,而启动的 App 则运行在另一个进程中,会涉及到进程间通信 (IPC),这种复杂的过程则需要 ActivityManagerService 作为中介来中转和处理。

ActivityManagerService 运行在 Android Framework 中,其是一个守护进程。Android 系统中,实现了 ActivityManager,通过其作为一个入口,来和 ActivityManagerService 打交道。ActivityManager 其背后的运作方式之核心就是 Binder 机制,下面大概看一下。

Binder 体系架构分为 Client 和 Server 两端,为了更方便地调用 Client,采用了 AIDL (Android 接口定义语言)的方式。ActivityManager 使用了代理模式:IActivityManager 对执行的命令抽象,包括常见的 startActivity()、showWaitingForDebugger() 和 finishActivity() 等方法。ActivityManagerProxy 相当于信使,其 Proxy 无须懂得具体的业务,只传递过去具体的指令。ActivityManagerService 是具体的执行者,而 ActivityManager 则是具体业务逻辑的外观类,负责核心的分发命令。如下图:

II. Launcher 至 ActivityManager 启动

点击 Launcher 中的 App 图标,将调用 Activity 的 startActivity() 方法。跟进去,看到会调用到 startActivityForResult() 方法,在该方法中,最后会调用到 mInstrumentation.execStartActivity() 方法,源码如下:

1
2
3
4
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options)
{

if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
// ...
} else {
// ...
}
}

可以看到,Instrumentation 执行 execStartActivity() 方法,其中的参数 mMainThread.getApplicationThread() 和 mToken 对象都是 IBinder 类型的,而 Binder 在跨进程调用中充当着 Token 的角色。事实上,多进程中 Binder Driver 保证其是唯一的。源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options)
{

IApplicationThread whoThread = (IApplicationThread) contextThread;
// ...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
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;
}

看到 ActivityManagerNative.getDefault().startActivity() 方法,实际上,getDefault() 返回的就是 Proxy 对象,起到代理的作用,其实现很简单,源码如下:

1
2
3
4
// 取回系统默认的全局 activity manager
static public IActivityManager getDefault() {
return gDefault.get();
}

IActivityManager 是对可以操作的接口的抽象,gDefault 返回了实现 IActivityManager 的单例,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
}
};

再看 IActivityManager 相关的这个方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 将 Binder 对象转变为 activity manager 接口,需要时生成 proxy
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 内部是如何工作的,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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 = Parcel.obtain();
Parcel reply = Parcel.obtain();
// 一堆写数据操作
data.writeInterfaceToken(IActivityManager.descriptor);
// ...
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;
}

// ...
}

ActivityManagerProxy 将 IBinder 作为构造函数的参数,注意看这一行代码:

1
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);

执行 IBinder 对象中的 transact() 方法,参数写入到 data 中;执行完毕后,再将结果写入到 reply 中。故而,起到了代理的作用,因为其只负责数据的传输。返回的 mRemote 的类型 IBinder 是什么?前述的单例方法里,有:

1
IBinder b = ServiceManager.getService("activity");

其返回的就是 ActivityManagerService!所有的系统服务都是 IBinder 对象,支持远程调用。此外,每个系统服务都会在 ServiceManager 中注册别名,而后,ServiceManager 通过其别名访问相应的系统服务。

在讲 ActivityManagerService 到进程启动之前,先来认识重要的Zygote 进程

III. Zygote 进程

Zygote 中文义为受精卵,意即其进程主要是分裂复制,事实上,所有的 App 进程都是通过对 Zygote 进程 Fork 而来。当app_process启动 Zygote 后,会预加载必要的 Java Classes 和资源 Resources,并启动 System Server,打开/dev/socket/zygotesocket 去监听其启动应用程序的请求。启动和加载 System Server 如下:

1
2
3
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String argv[]) {
// ...
// 注册 Zygote socket
registerZygoteSocket(socketName);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
// 预加载资源
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// 完成 zygote 的初始化配置
SamplingProfilerIntegration.writeZygoteSnapshot();
// 启动后,执行个初步的 gc 以清除
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
// 触发 gc
gcAndFinalize();
// 启动 System Server
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
// ...
}

大致的流程示意图如下:

应用程序的运行,依托于相应的 Dalvik(ART) 虚拟机环境。但是,每次启动的开销较大,通过 Fork Zygote 的进程,能够较好地提升效率。在这个过程中,采用了 Copy-on-Write 的方式,极大地复用了 Zygote 上的资源。

好,认识完毕,接下来看 ActivityManagerService 至进程启动。

IV. ActivityManagerService 至进程启动

ActivityManagerService 接收到四大组件如 Activity 的 Intent 请求后,会检索是否需要新建进程,且以 Activity 为例,其他组件与此同理。

ActivityManagerService 启动 Activity 之前,执行 resolveIntent() 方法,得到相应的 ResolveInfo,再调用 startActivityLocked() 启动 Activity。源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try {
ResolveInfo rInfo =
AppGlobals.getPackageManager().resolveIntent(
intent, null,
PackageManager.MATCH_DEFAULT_ONLY
| ActivityManagerService.STOCK_PM_FLAGS, userId);
aInfo = rInfo != null ? rInfo.activityInfo : null;
aInfo = mService.getActivityInfoForUser(aInfo, userId);
} catch (RemoteException e) {
aInfo = null;
}

int res = startActivityLocked(caller, intent, resolvedType, aInfo,
voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, startFlags, options,
componentSpecified, null, container, inTask);

判断是否需要新建进程,执行 startSpecificActivityLocked() 方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig)
{

ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);

r.task.stack.setLaunchTime(r);

if (app != null && app.thread != null) {
try {
// ...
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}

mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}

对 ProcessRecord 作判断,ProcessRecord 即响应的进程记录。若存在相应的进程,则启动有关的 Activity,否则创建新的进程。其中,mService.startProcessLocked() 方法开启进程,其源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs)
{

// ...
// 启动进程,返回包含新进程 PID 的结果,或者抛出运行时异常
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
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);
// ...
}

其内部调用到 Process.start() 方法,指定 android.app.ActivityThread 作为进程的入口。进程启动后,将调用 android.app.ActivityThread 的 main() 方法。Process.start() 方法中,调用的是 startViaZygote() 方法,方法内,通过 openZygoteSocketIfNeeded() 方法打开 Zygote 的 socket,借助 zygoteSendArgsAndGetResult() 交互。Zygote 开启一个 socket 监听功能,监听需要创建 Process 的请求。

再看 ZygoteInit.runSelectLoop() 方法,这里,不断地取 Socket 建立的连接 (ZygoteConnectioin),之后,调用 ZygoteConnection 里的 runOnce() 方法。runSelectLoop() 方法的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];

fds.add(sServerSocket.getFileDescriptor());
peers.add(null);

int loopCount = GC_LOOP_COUNT;
while (true) {
int index;

// 在 select() 方法里阻塞之前调用 gc() 方法,不要每次都调用
if (loopCount <= 0) {
gc();
loopCount = GC_LOOP_COUNT;
} else {
loopCount--;
}

// ...

if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDescriptor());
} else {
boolean done;
done = peers.get(index).runOnce();
// ...
}
}
}

ZygoteConnection.runOnce() 方法里,fork 了 Zygote 进程即应用进程,返回相应的 process id,其具体实现为本地方法。获得相应的 process id,接下来看应用进程的初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);

try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
} else {
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}

着重进行了各种 I/O 操作,进到 handleChildProc() 方法里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)

throws ZygoteInit.MethodAndArgsCaller {


if (parsedArgs.runtimeInit) {
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
pipeFd, parsedArgs.remainingArgs);
} else {
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}

try {
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
} catch (RuntimeException ex) {
logAndPrintError(newStderr, "Error starting.", ex);
}
}

重点看以上代码中的 RuntimeInit.zygoteInit() 方法,其初始化了相应的进程,实现了相应 AndroidRuntime 的初始化,并初始化 Binder Driver 相关的文件。执行完此方法,应用进程便具备与相应系统服务 IPC 通信的能力;此外,还有 ZygoteInit.invokeStaticMain() 方法,调用了进程的 main() 方法,其源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void invokeStaticMain(ClassLoader loader,
String className, String[] argv)

throws ZygoteInit.MethodAndArgsCaller {

Class<?> cl;

try {
cl = loader.loadClass(className);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}

// 此抛出会在 ZygoteInit.main() 中捕获,被调用异常的 run() 方法响应,
// 清除所有要求设置进程的栈帧
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

通过反射调用 ZygoteInit.MethodAndArgsCaller,这就是相应的 ActivityThread 里的 main() 方法,其运行的进程即 UI 线程(主线程)。

至此,Application 的启动流程完毕,如下图所示:

总结

经过上述分析,最终总结图如下:

点击 Launcher 中的 Icon,发送广播,启动 Service 等组件的跳转,通过 AndroidManagerProxy 来中转。AndroidManagerProxy 向 System Server 请求名为 Activity 的 ActivityManagerService 的 Binder 对象。该 Binder 对象大致可以粗略地看作是 ActivityManagerService 的句柄,从 Binder 对象实际操作 ActivityManagerService。

ActivityManagerService 启动相应的组件时,会先判断是否有相应的 ProcessRecord,若不存在,则新建相应的应用进程。ActivityManagerService 通过 Socket 通信方式和 Zygote 进行协商,Zygote 在其监听的/dev/socket/zygotesocket 中发现有需要创建进程的请求后,会 fork 自身,并返回相应的 process id。

而后,Process 会进行相应的初始化,使其具备与系统服务进行 IPC 通信的能力,此后,调用 Activity Thread 中的 main() 方法,开启 Looper,启动主线程。Application 的启动流程结束。

至此,探究 Android Application 的启动流程到此结束。

本人才疏学浅,如有疏漏错误之处,望读者中有识之士不吝赐教,谢谢。

1
Email: [email protected] / WeChat: Wolverine623

您也可以关注我个人的微信公众号码农六哥第一时间获得博客的更新通知,或后台留言与我交流

参考文献

1.http://blog.csdn.net/luoshengyang/article/details/6689748

2.http://multi-core-dump.blogspot.hk/2010/04/android-application-launch.html

3.http://www.woaitqs.cc/android/2016/06/21/activity-service.html