安卓启动相关以及架构设计相关
我们知道安卓大多数是服务等的启动是伴随着init进程启动一起启动,这个init进程类似于linux的init,进程pid为1。
读过安卓源码的人都应该很熟悉init会读取init.rc和init.xxx.rc等,想必也读取过关于rc的相关readme。文档中介绍了Actions、Service、Command、Options。其中我只摘取Service的一段原文介绍(此service非framework层的service,安卓把每个由init运行的程序或者进程叫做服务,):
Services
----------------------------------------------------------------------------------------------------------------
Services are programs which init launches and(optionally) restarts when they exit. Services take the form of:
service<name> <pathname> [ <argument> ]* <option>
<option>
...
Options
----------------------------------------------------------------------------------------------------------------
介绍的很明了,服务是init运行起来的程序或者可选地重启当它们退出的时候。服务格式如下:
service <name> <pathname> [<argument> ]*
<option>
<option>
...
Options其中option是选项
在init中service结构体(只显示重要部分):
struct service {
/* list of all services */
struct listnode slist;服务链表,内核结构应该是双向链表
const char *name;服务名称
const char *classname;服务对应的class类
unsigned flags;
pid_t pid;进程id
uid_t uid;用户uid
gid_t gid;组id
char *seclabel;
struct socketinfo *sockets;
struct svcenvinfo *envvars;
struct action onrestart; /* Actions to execute on restart. */
};
好我们现在理解了服务,那在看看init.rc中包含的一个我们比较关注的服务(也算一个例子):
service zygote/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote 666
启动一个名字为zygote的服务,它的路径名为/system/bin/app_process,参数为
-Xzygote /system/bin--zygote --start-system-server,选项为socket zygote 666(打开socket)
// Everything upto ‘--‘ or first non ‘-‘ arg goes to the vm这句摘自app_main.cpp
这句是对参数-Xzygote /system/bin --zygote的一个很好的诠释,-Xzygote是传递给vm的参数,而--zygote --start-system-server是传递给/system/bin的参数,意思是启动system_server,其父进程是zygote。
zygote作为一个service底层通过相应的alloc和fork实现。
用adb连接我自己的htc设备,然后ps显示zygote和system_server进程如下:
从上图看到system_server的ppid为1527,zygote的pid为1527而ppid为1,得出zygote是由init进程fork出来的,而system_server由zygote进程fork出来的。
Service启动的四种模式
Zygote、SystemServer、Application、Tool
所有这一切构成了安卓系统的服务,在init启动时会都被启动起来。
从Zygote开始
zygote代码集合
查看过源码的人可以了解到,zygote重要的相关代码包含如下:
framework/base/cmds/app_main.cpp
fremework/base/core/java/com/android/internal/os/ZygoteInit.java
fremework/base/core/java/com/android/internal/os/ZygoteConnection.java
libcore/dalvik/java/dalvik/system/Zygote.java
dalvik/vm/native/ dalvik_system_Zygote.cpp
frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp
当然zygote相关代码比显示的要多,但是上面这些已经足够你了解zygote了。
现在我们来讲解一下zygote到底做了什么,当然这些讲解的依据是上面讲到的相关zygote源码。但是我不会具体列出流程出自哪个文件,因为这样讲起来比较费力气,所以我这里只是讲解流程逻辑。
app_process创造了zygote
可以从上面的init.rc和相关Readme介绍得到,zygote是由/system/app_process这个bin加一些参数创造出来的,所以你不用在纠结什么zygote和app_process关系。
另外一方面init进程fork出来了zygote进程,而zygote进程又相继孵化出来了system_server进程等其他进程。
那是不是可以理解app_process就是init进程呢?这个问题我用一个例子回答你。我们从7岁开始上学到20多岁毕业,这段时间中我们经历了小学九年义务教育,经历了高中三年教育,经历了大学四年教育。然后我问你,你读高一,那么这个高一能代表你的所有学习经历吗?学习就好比init进程,我们学习经历的小学中学高中大学,就好比init一点一点一步一步做的事情,那么通过一个可执行bin app_process启动zygote也是其中之一的工作,当然init的工作可远不止如此。同样app_process也不只创造了zygote,还做了其他事情。
看一段代码(摘自app_main.cpp):
classAppRuntime:publicAndroidRuntime{……}
AppRuntimeruntime;
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server":"");
} elseif(className) {
// Remainder of args get passed to startup class main()
runtime.mClassName = className;
runtime.mArgC = argc - i;
runtime.mArgV = argv + i;
runtime.start("com.android.internal.os.RuntimeInit",
application ? "application":"tool");
}
上面代码(app_process)说明了AppRuntime继承自AndroidRuntime,同时获得AndroidRuntime实例。如果是zygote启动它,怎么启动runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server":"");
如果不是通过传递过来的类的参数启动它runtime.start("com.android.internal.os.RuntimeInit",
application ? "application":"tool");
做完这些事情app_process就寿终正寝了。
Zygote做了些什么,ZygoteInit
init进程启动的时候zygote被作为一种服务启动起来,并且赋予了进程名字为zygote。
所做之事:
n SamplingProfilerIntegration.start();开启性能监控,这个对讲解没什么意义
n registerZygoteSocket();注册socket
n preloadClasses();在preloaded-classes文件中,这里面包名了所有安卓环境需要的服务和工具和所有类,有兴趣的可以去看看这个文件。
n preloadResources();准备preloadClasses()需要的资源。
n startSystemServer();启动system_server
n 如果是zygote 模式,runForkMode();
n 否则runSelectLoopMode();
n closeServerSocket();关闭socket
n Exception执行caller.run();
上面proloadclasses实际上并没有真正的实例化类,而是仅仅加载类的vm中。
runForkMode
while (true) {
ZygoteConnection peer = acceptCommandPeer();
int pid;
pid = Zygote.fork();
if (pid == 0) {
……
peer.run();
break;
}
runForkMode 方法首先fork新的进程,并且对fork出来的进程执行run方法,那么Zygote.fork做了什么呢?
首先它执行nativeFork然后调用dalvik native代码forkAndSpecializeCommon这里我只选择了最重要的大家能看懂的一行代码,其他代码有兴趣的可以去源码中研究:
pid = fork();Linux中的经典fork。
从上面代码可以看出Zygote确实是fork出来了进程,其中包含system_server,而且zygote作为后台进程无限的从socket接收到fork请求,来fork出新的进程。
fork出来的进程执行run方法,run方法执行runOnce,runOnce做了什么,请看下一节。实际这里调用这个方法它什么都没做。
runSelectLoopMode
这里最主要的是它调用了runOnce,而runOnce最核心的一行代码是:
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName);
这个方法调用nativeForkAndSpecialize在调用Dalvik_dalvik_system_Zygote_fork,这里只是常规的fork。
SystemServer为一切安卓环境做准备
zygote启动完成之后,它启动了system_server,然后自己进入了fork模式等待fork新的进程。
启动system_server
n Zygote.forkSystemServer//最终调用forkAndSpecializeCommon fork出system_server
n handleSystemServerProcess//因为invokeWith为空所以它执行了RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs)-------------------->
redirectLogStreams();//重置输入错误流
commonInit();//设置时区,http代理,安装NetworkManagementSocketTagger
nativeZygoteInit();//最终调用onZygoteInit
||sp<ProcessState>proc = ProcessState::self();
||proc->startThreadPool();//创建线程,启动
applicationInit(targetSdkVersion,argv);//执行SystemServer的main函数,看到了没才刚刚开始哦。
进入SystemServer类的main函数,其中主要执行了以下方法:
n System.loadLibrary("android_servers");//加载libandroid_servers.so
n init1(args);//掉用system_init();
调用system_init
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
获得processstate实例,获得servicemanager实例。
……
AndroidRuntime* runtime = AndroidRuntime::getRuntime();
获得启动安卓的vm
JNIEnv* env = runtime->getJNIEnv();
jclass clazz = env->FindClass("com/android/server/SystemServer");
jmethodID methodId = env->GetStaticMethodID(clazz, "init2","()V");
env->CallStaticVoidMethod(clazz, methodId);
加载SystemServer类并执行init2方法
ProcessState::self()->startThreadPool();
创建一个线程,不知道为什么google的工程师把它命名为startThreadPool
,pool很容易影响人的思维,但是当你查看代码的时候发现它最终就调用了一个pthread_create无非就是创建一个线程。
IPCThreadState::self()->joinThreadPool();
joinThreadPool实现有点复杂,我摘几行最重要的代码:
do {
……
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
result = executeCommand(cmd);
}
……
if(result == TIMED_OUT &&!isMain) {
break;
}
……
} while (result != -ECONNREFUSED && result != -EBADF);
talkWithDriver(false);
这个函数在循环中重复执行下列动作:
1.talkWithDriver 通过ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)读取请求和写回结果。
2.executeCommand 执行相应的请求,反正也是和binder相关的
凡是程序中包含有joinThreadPool这段代码,它就具备和binder通讯的能力了。
有些人总是看到pool就喜欢和什么池联系起来,但是我看了几遍源码都没看见对于池的操作,至于google为什么这么设计我不知道。
init2
代码来源于SystemServer
Thread thr = new ServerThread();
thr.start();
首先ServerThread是继承自Thread的,那么上面这两行我们已经很清楚了就是启动一个线程。
在线程里做了什么呢,记得之前zygote启动的时候proload中的proclasses吗,当时只是加载了所有的class到vm中,但是并没有实例化并投入到工作中,而且zygote启动之后进入了loop模式等待socket请求来fock新的进程,其他的事情它就撒手不管了,就交给了system_server。到现在为止,安卓的环境还没有准备充足,什么我们平时常常听到了ActivityManagerService呀,什么PackageManagerService呀,各种服务各种应用吧,凡是为安卓大多数安卓的环境这里几乎都准备了。
run方法
下面让我们看一些重要的源码吧(感兴趣的可以自己仔细研习代码):
……
Looper.prepareMainLooper();
准备loop,进入loop
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
BinderInternal.disableBackgroundScheduling(true);
设置进程优先权,设置binder禁止内部后台调度
……
HandlerThread uiHandlerThread = newHandlerThread("UI");
uiHandlerThread.start();
Handler uiHandler = new Handler(uiHandlerThread.getLooper());
uiHandler.post();
HandlerThread wmHandlerThread = newHandlerThread("WindowManager");
wmHandlerThread.start();
Handler wmHandler = newHandler(wmHandlerThread.getLooper());
wmHandler.post();
UI和WindowManager进入handle状态
下面就是实例化各种服务了,其中包含实例化,向ServiceManager中注册服务,调用各种服务类的核心方法等。代码太一目了然了,顺着代码你可以去相关类去看具体方法,从而能得知所有启动过程和调用方法执行了什么。
installer = new Installer();
installer.ping();
ServiceManager.addService("entropy",newEntropyMixer());
power = new PowerManagerService();
//电源管理
ServiceManager.addService(Context.POWER_SERVICE,power);
context =ActivityManagerService.main(factoryTest);
display = newDisplayManagerService(context, wmHandler, uiHandler);
ServiceManager.addService(Context.DISPLAY_SERVICE,display, true);
telephonyRegistry = newTelephonyRegistry(context);
ServiceManager.addService("telephony.registry",telephonyRegistry);
ServiceManager.addService(Context.SCHEDULING_POLICY_SERVICE,
new SchedulingPolicyService());
……
pm =PackageManagerService.main(context, installer,
factoryTest !=SystemServer.FACTORY_TEST_OFF,
onlyCore);
//包管理
ActivityManagerService.setSystemProcess();
ServiceManager.addService(Context.USER_SERVICE,
UserManagerService.getInstance());
mContentResolver= context.getContentResolver();
accountManager = newAccountManagerService(context);
ServiceManager.addService(Context.ACCOUNT_SERVICE,accountManager);
……实在是太多ManagerService和太多的Service了,不写了自己去看吧
power.systemReady(twilight, dreamy);
pm.systemReady();
……各种ready各种初始化各种调用主要函数不写了
startSystemUi(contextF);
context.startServiceAsUser(intent,UserHandle.OWNER);
启动系统UI
Looper.loop();
进入loop模式,handleMessage去了。后面略。
至此SystemServer就算讲完了,通过上面你应该知道它是什么时候被启动的已经启动后它做了些什么。
ServiceManager
ServiceManager是做什么的呢,其实它就是一个管理framework层各种服务的。它内部有一个结构体,是一个链表结构,每个节点对应一个服务,当执行SystemServer时它的run方法里面的所有服务都会向ServiceManager进行注册。
一个服务本身并不完全由纯java编写,也许有一些是这样,因为我并没有看过所有代码不敢妄断,但是通常一个服务是由java和jni和native代码一起编写。而且通常状态下如果一个service会为上层应用提供服务那么这个service通常会有一个binder的stub,这个stub叫做桩,类似于代理但是又不能说是代理,这是rpc协议和机理所致。如果做过java rpc的人或许会对此并不陌生。
通用规则:
所有的XXXManager都是作为XXX的管理者。
所有的XXXManagerService或者XXXService几乎都是作为XXX类型对上层通过binder通讯而为其服务的独立进程。
svcinfo结构体
struct svcinfo
{
structsvcinfo *next;下一个服务
void*ptr;服务指向的地址
structbinder_deathdeath;
intallow_isolated;
unsignedlen;
uint16_t name[0];服务名称
};
structsvcinfo *svclist = 0;
这个结构体就是一个对应service list的结构体,它里面包含所有服务。初始时这个链表为0也就是NULL。
servicemanager提供的方法
查找服务、添加服务、释放svc结构、处理svc其中包含(查找服务、添加服务、检查服务、列出所有服务、获得服务)。
通过读取servicemanager的main函数我们得知它首先打开了binder,并且把自己变成了BINDER_SERVICE_MANAGER,然后进入了无限循环状态,等待其他service的binder通讯,它负责各个service之间的通讯通过binder,它作为了一个桥梁。
binder相关
首先binder作为一种驱动设计,用于进程间通讯,使用rpc协议。遵循linux驱动设计。在类unix世界一切皆文件,所有你能在binder相关源文件看到,访问binder和访问文件一样通过一个open就可以了,用户层和binder的通讯命令借助底层实现的ioctl函数。
因为安卓世界里,几乎每一个service都是作为独立进程运行的,都是由zygote进程fork出来的,所有各个进程是独立的,他们有自己的进程空间,所以为了彼此通讯,安卓设计了有别的binder机制。