本文主要内容
- Activity启动流程
- 进程启动过程
- 总结
Android应用可被多种方式启动,包括启动服务、activity,接收广播,ContentProvider被查询也会启动应用。如果应用是persitant应用,系统则会自动地去启动它。
本文主要阐述activity的启动,最后是一些总结性的东西。
Activity启动流程
先来看一张流程图:
activity启动的流程非常非常的多,代码阅读比较困难,我们不一一读了,可以跟着这条线,细细推敲,我们只讲几个重点。
其实activity启动的逻辑主要是这几个部分:
- 权限控制
- activity启动模式导致的不同activity stack策略
- 进程启动
- IPC通信启动activity
权限控制以及启动模式相关内容,本文不深入探讨,进程启动我们下个小节再讲,这里主要阐述下IPC通信启动activity。
如果我们以桌面上启动音乐为例,桌面和音乐分别属于不同的进程,而ams也是跑在系统进程当中的,三个不同进程之间是如何通信的?
桌面调用ContextImpl的startActivity方法,最后将通过ActivityManagerNative.getDefault(),获取AMS的IPC代理,实现与AMS通信。而AMS最后要来启动音乐,则会收到音乐的ApplicationThread的实例,ApplicationThread其实是一个binder对象,AMS就是通过它才能与音乐进程进行通信,最终创建音乐进程,并启动activity。
进程启动
Android中所有apk的进程都是由zygote启动的,zygote中文名为受精卵,它调用linux接口fork,创建进程。
AMS与zygote采用socket进行进程间的通信,实现进程创建。
zygote创建进程的时候,某种程度上是复制,它会创建一个vm实例,其中会包含一些预加载的系统类以及资源,这样能加快或者方便apk调用。
原理图如上,zygote接收socket通信的指令并读取,然后fork一个VM实例出来,创建新进程并执行这个进程。
既然是socket通信,必然会有一个服务端,android中这个服务端是ZygoteInit,我们来看它的main方法:
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
boolean startSystemServer = false;
//注意,zygote这是服务端的名字,类似于java上socket中的端口号,接下来会用到
String socketName = "zygote";
String abiList = null;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
//使用socket名字,来创建socket服务端
registerZygoteSocket(socketName);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
gcAndFinalize();
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
//runSelectLoop方法中是一个死循环,不停地接收指令并fock进程
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
由代码可知,和java类似,声明socket服务端的端口号并且采用死循环,读取客户端指令并执行。
AMS在startProcessLocked方法中调用Process.start方法,来启动进程,具体流程如下所示:
注意:Process类作为客户端,而ZygoteInit作为服务端,ZygoteInit中的runSelectLoop方法一直死循环,当接到Process创建进程指令时,就会去调用ZygoteConnection的runOnce方法,完成进程创建。
比较有意思的是:
entryPoint = "android.app.ActivityThread";
Process.start(entryPoint ....
public static final ProcessStartResult start(final String processClass,
可以看到Process启动进程的processClass为ActivityThread,而Java语言是在进程启动时执行main方法,所以当apk的进程创建后,第一个被执行的方法就是ActivityThread的main方法。
总结
- activity的onCreate方法
activity在ActivityThread当中被启动后,由Instrumentation的newActivity方法完成实例创建:
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
因为activity类名未知,所以最后创建实例的必是反射创建,而且还要使用正确的ClassLoader。
cl由LoadApk类获取,查看其源码即知,这个ClassLoader是正确的,有点类似于动态加载中指定apk路径构建ClassLoader,它能正确加载到activity。
- 设计思路
回想activity的创建流程,如果这个工作由我们来做,我们应该要怎么设计它?android为了更为简单易用,将复杂的IPC通信以及其它的都封装得很完美,用户只要声明activity即可,这实在是完美的作品。
其实我们学习过很多的设计模式,但事到临头总是用不出来,有时想想这些常见的流程、机制,都有很多值得我们学习的地方