Android framework 应用进程如何启动

慕课网 剖析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才能继续启动应用的各个组件。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值