慕课网 剖析framework 笔记
3-1 应用进程如何启动
考察:
Linux如何启动进程,有什么系统调用
Android里应用进程启动的基本流程,进程由谁启动,谁发起
深入理解应用进程启动的原理,各个组件之间的通信过程
1,进程启动方式
前面讲过,两种。
都是 通过fork,子进程返回的pid是0,父进程返回的pid是子进程的pid。
区别:
第二种在子进程里多了一个execve(path, argv, env);
1,应用进程启动原理
1)什么时候触发的进程启动?谁发起的?
2)进程是谁启动的?怎么启动?
谁发起,和谁启动,是两码事
1)什么时候触发的进程启动?
Android没有提供接口可以启动进程,都是被动启动,
被动启动:启动组件时,如果发现组件所在的进程没有启动,则启动进程。这是Framework里面做的
下面是framework做的启动进程的代码,无论是启动acvitiy还是启动service,只要是启动组件,都会做这个判断:
//查找这个组件所在的进程,每个进程对应一个ProcessRecord,
ProcessRecord app = getProcessRecordLocked(...);
//找到了,thread也不能为空
if(app != null && app.thread != null){
//进程已经启动,这里可以启动组件
return;
}
//如果没有找到这个组件对应的ProcessRecord,就执行这个函数启动进程
startProcessLocked(r.processName);
app.thread是什么?为什么它也不能是NULL?
如图:
两个角色,AMS和AP
AP可以通过ServiceManager拿到AMS的binder句柄:IActiivtyManager,然后AP就可以向AMS发起binder调用
但是这样是单向调用,有时系统还要通知AP,系统要调用组件的生命周期,系统也要持有AP的Binder句柄才行
所以AMS里,AP的binder句柄就是IApplicationThread,它不是一个线程,不要被名字欺骗,它就是一个Binder句柄
AMS怎么会持有AP的binder句柄?AP也没有把binder句柄注册到ServiceManager,
AP进程在启动时,会调IAcivitiyManager的一个函数向AMS报告,一方面告诉AMS,AP已经启动,另一方面是向AMS注册自己的IApplicationThread这个binder句柄
AP进程启动后要执行的入口函数:
多复杂的APP都可以被这4句话概括:
public static void main(String[] args){
//创建主线程的looper
Looper.prepareMainLooper();
//不要被骗,这其实不是什么线程,就是普通的java对象
ActivityThread thread = new ActivityThread();
//
thread.attach(false);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
//thread.attach()做了什么?
//先获取AMS的binder对象
final IActivityManager mgr = ActivityManagerNative.getDefault();
//向AMS报告,AP启动好了,参数AppThread是AMS持有的AP端的binder句柄,这样AMS就可以向AP发起binder调用了。
mgr.attachApplication(mAppThread);
所以对于AMS来说,AP怎么算启动完成?
//1 AMS向zygote发起启动AP进程的请求后,zygote启动进程,会返回进程的pid给AMS
//2,AP启动好后,亲自告诉AMS启动完成
//可能进程启动了,AP没来得及向AMS注册binder,这时又有另一个组件要启动了,此时会不会重复启动这个AP进程?
对于这个问题,startProcessLocked里面有判断
//ProcessRecord不为null,
//app.pid不为空,这个pid是什么时候赋值的?AMS向zygote请求启动ap,zygote返回AP pid给AMS,AMS保存pid到ProcessRecord.pid
if(app != null && app.pid > 0){
//AP启动完毕,会通知AMS,传了这个IThread binder对象
//AMS就会把这个Thread保存在app.thread
//此时是AP已经启动,但是还没来得及报告给AMS,所以要等待AP come up
if(app.thread == null){
//we already have the app running, or are waiting for it to come up(we hava a pid but not yet its thread),
//so keep it
return app;
}
}
那么进程启动好了,组件什么时候启动?
以启动service为例,AP要启动service。请求发给AMS,AMS会调用到BingUpServiceLocked
String bringUpServiceLocked(ServiceRecord r, String procName,){
ProcessRecord app = mAm.getProcessRecordLocked(procName);
//如果有了AP的ProcessRecord,而且AP也报告给了AMS,就真的启动service
if(app != null && app.thread != null){
realStartServiceLocked(r, app, execInFg);
return null;
}
//如果AP进程还没有启动,启动AP
if(app == null){
app = mAm.startProcessLocked(procName, ...);
}
//如果AP还没有报告,等着
//如果PendingService列表里面没有他,就把他加到list里面,
if(!mPendingServices.contains(r)){
mPendingService.add(r);
}
}
什么时候处理PendingServicelist?
AP启动后会向AMS报告,这时会调attachApplicationLocked,它会处理pending的组件
boolean attachApplicationLocked(ProcessRecord proc, String processName){
if(mPendingServices.size() > 0){
ServiceRecord sr = null;
for(int i=0; i<mPendingServices.size();i++){
sr = mPendingServices.get(i);
mPendingServices.remove(i);
i--;
//取到ServiceRecord后,会真正启动service
realStartServicLocked(sr, proc, sr.creratedFromtFg);
}
}
}
所以启动service时,如果AP进程还没启动,那就把service加到Pending list里面
等AP启动后报告到AMS,再启动这些service
2,进程是怎么启动的?
startProcessLocked
前面提过,启动进程是在AMS的startProcessLocked函数做的,
它不会直接启动进程,只是发起了启动进程:
1,打开socket,通过openZygoteSocketIfNeeded
2,通过socket发送参数列表,有个重要参数: AP java类名(有入口main函数),通过zygoteSendArgsAndGetResult
3,等到结果:zygote启动完进程后,返回进程的pid
那zygote怎么处理socket请求?
如果zygote收到了消息,就调用runOnce函数
这个前面应该讲过:
boolean runOnce(){
String[] args = readArgumentList(); //读取参数列表
int pid = Zygote.fotkAndSpecialize(); //根据参数启动子进程
if(pid == 0){
//in child
handleChildProc(args, ...);
//在子进程里面干活,其实执行的就是java类得main函数(入口函数),java类名来自上面读取的参数列表。
//参数列表是AMS通过socket跨进程发过来的,类名就是ActivityThread.main(),
//也就是说,应用程序进程执行后会马上执行ActivityThread.main()函数
//AcitivityThread类的main做两件事:
//1,启动主线程消息循环
//2,向AMS报告
return true;
}
}
作业:
1,为什么是zygote创建进程,而不是systemServer,
2,AMS和zygote为什么不用Binder通信?
总结:你知道应用进程怎么启动的吗?
1,应用进程是什么时候启动的?什么场景下启动的?
是在启动应用组件时,如启动activity,service等,会先判断应用组件所在进程有没有启动,如果没有就启动金城。
2,是谁发起的?
是AMS向zygote发起的,通过socket,zygote收到就启动进程,他们通信没用binder,用的socket,
3,zygote fork出AP进程后,会执行入口函数:ActivityThread的main函数,这个入口函数的java类名是AMS通过socket发给zygote的,
4,进程启动后要向AMS报告,这样启动才算结束,
因为只有向AMS报告了,这样AMS才能继续启动应用的各个组件。