Android 应用进程启动过程

作者 : 开心源码 本文共11672个字,预计阅读时间需要30分钟 发布时间: 2022-05-12 共142人阅读

Android应用进程启动流程

注意,这里讲的是应用进程的启动流程,不是应用的启动流程

本文承接部分Android系统启动流程的内容,建议有欲望的童鞋先看看:传送门

一:简介

想要启动一个应用程序,首先要保证这个应用所需要的应用程序进程已经启动。

AMS在启动应用程序时会检查这个应用所需要的应用程序进程能否存在,假如不存在就会请求Zygote进程启动一个新的应用程序进程。这个流程用到的通讯方式,就是我们在Android系统启动流程中提到过的,Zygote Server端的 Socket(这个socketName就是zygote)。

Android系统启动流程一文中提到过,Zygote在注册好了Socket之后,会调用一个方法:zygoteServer.runSelectLoop(),这样就会进入一个循环,等待AMS请求Zygote来创立新的应用程序进程。Zygote进程通过 fork自身创立应用程序进程,这样的应用程序进程就会取得Zygote进程在启动时创立的java虚拟机实例。当然,在应用程序进程创立过程中除了获取虚拟机实例外,还会创立 Binder线程池以及 Looper消息队列循环,这样运行在应用进程中的应用程序即可以方便地使用Binder进行进程间通信以及解决消息了。

二:应用程序进程的启动过程

1.AMS发送指令

AMS想要启动应用程序进程,就需要向Zygote进程发送创立应用进程的请求,AMS会通过调用
startProcessLocked方法向Zygote发送进程请求。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java:

private final void startProcessLocked(ProcessRecord app,String hostingType,String hostingNameStr,String abiOverride,String entryPoint,String entryPointArgs){    ...    //获取要创立的应用程序进程的客户ID    int uid=app.uid;        ...    //判断能否隔离    if(!app.isolated){        ...        //对gids进行创立和赋值        if(ArrayUtils.isEmpty(permGids)){            gids=new int[3];        }else{            gids=new int[permGids.length+3];            System.arraycopy(permGids,0,gids,3,permGids.length);        }        gids[0]=UserHandle.getSharedAppGid(UserHandle.getAppId(uid));        gids[1]=UserHandle.getCacheAppGid(UserHandle.getAppId(uid));        gids[2]=UserHandle.getUserGid(UserHandle.getUserId(uid));    }    ...    //准备反射ActivityThread    if(entryPoint==null) entryPoint="android.app.ActivityThread";        ...    //启动应用程序进程,参数过长请忽略    startResult=Process.start(entryPoint,app.processName,uid,uid,gids,debugFlags,mountExternal,app.info.targetSdkVersion,seInfo,requiredAbi,instructionSet,app.info.dataDir,invokeWith,entryPointArgs);        ...}

该方法主要做了三件事,获得了uid,创立并赋值了gids,调用Process的start方法并传入ActivityThread等启动参数,准备启动进程。

接下来看看Process的start方法。

frameworks/base/core/java/android/os/ZygoteProcess.java:

//参数过长请忽略那些不太重要的public final Process.ProcessStartResult start(final String processClass,final String niceName,int uid,int gid,int[] gids,int debugFlags,int mountExternal,int targetSdkVersion,String seInfo,String abi,String instructionSet,String appDataDir,String invokeWith,String[] zygoteArgs){    try{        //调用了startViaZygote方法        return startViaZygote(processClass,niceName,uid,gid,gids,debugFlags,mountExternal,targetSdkVersion,seInfo,abi,instructionSet,appDataDir,invokeWith,zygoteArgs);    }catch(ZygoteStartFailedEx ex){        ...        throw new RuntimeException("Starting VM process through Zygote failed",ex)    }}...//参数过长请忽略那些不太重要的private Process.ProcessStartResult startViaZygote(final String processClass,final String niceName,final int uid,final int gid,final int[] gids, int debugFlags,int mountExternal,int targetSdkVersion,String seInfo,String abi,String instructionSet,String appDataDir,String invokeWith,String[] extraArgs){    ...    synchronized(mLock){        //这两个方法,zygoteSendArgsAndGetResult以及openZygoteSocketifNeeded才是重点        return zygoteSendArgsAndGetResult(openZygoteSocketifNeeded(abi),argsForZygote)    }}

调来调去没有什么新鲜的,接下来就有两个方法,zygoteSendArgsAndGetResult方法,和openZygoteSocketifNeeded方法,这两个才是重点。

frameworks/base/core/java/android/os/ZygoteProcess.java:

private static Process.ProcessStartResult zygoteSendArgsAndGetResult(ZygoteState zygoteState,ArrayList<String> args){    try{        int sz=args.size();        for(int i=0;i<sz;i++){            if(args.get(i).indexOf('\n') >= 0){                throw new ZygoteStartFailedEx("embedded newlines not allowed");            }        }        final BufferedWriter writer = zygoteState.writer;        final DataInputStream inputStream = zygoteState.inputStream;        writer.write(Integer.toString(args.size()));        write.newLine();        for(int i = 0; i < sz; i++){            String arg=args.get(i);            writer.write(arg);            writer.newLine();        }        writer.flush();        Process.ProcessStartResult result=new Process.ProcessStartResult();        result.pid=inputStream.readInt();        result.usingWrapper=inputStream.readBoolean();                if(result.pid<0){            throw new ZygoteStartFailedEx("fork() failed");        }        return result;    }else{        zygoteState.close();        throw new ZygoteStartFailedEx(ex);    }}

从上面的读写操作,我们仿佛已经看到了Socket通信的过程。接下来ZygoteProcess中应该就有与Zygote建立Socket链接的部分了。

frameworks/base/core/java/android/os/ZygoteProcess.java:

private ZygoteState openZygoteSocketIfNeeded(String abi){    //假如与Zygote未建立连接或者者连接已断开    if(primaryZygoteState == null || primaryZygoteState.isClosed()){        try{            //尝试与Zygote进程建立连接            primaryZygoteState = ZygoteState.connect(mSocket);        }catch(IOException ioe){            throw new ZygoteStartFailedEx("Error connecting to primary zygote",ioe);        }    }    //连接Zygote主模式返回的ZygoteState能否与启动应用程序进程所需要的ABI匹配    if(primaryZygoteState.matches(abi)){        return primaryZygoteState;    }        //假如不匹配,则尝试连接Zygote的辅模式    if(secondaryZygoteState == null || secondaryZygoteState.isClosed()){        try{            //尝试与Zygote进程再次建立连接            secondaryZygoteState = ZygoteState.connect(mSecondarySocket);        }catch(IOException ioe){            throw new ZygoteStartFailedEx("Error connecting to Secondary zygote",ioe);        }    }        //连接Zygote辅模式返回的ZygoteState能否与启动应用进程所需要的ABI匹配    if(secondaryZygoteState.matched(abi)){        return secondaryZygoteState;    }    throw new ZygoteStartFailedEx("Unsupported zygote ABI:"+abi);}

确实,在这段代码中我们看到了AMS尝试与Zygote建立Socket通信的代码。

这里有两个概念:

1.ABI:abi全称Application binary interface(应用程序二进制接口),主要针对各种手机CPU架构不同,作出的一套适配规则。大家可以理解下介绍:传送门。

2.Zygote辅模式:在上一篇文章《Android系统启动流程》详情过,Zygote启动脚本分为4种:

1.init.zygote32.rc

2.init.zygote32_64.rc

3.init.zygote64.rc

4.init.zygote64_32.rc

对于采用的是init.zygote32_64.rc或者者init.zygote64_32.rc的Zygote,Socket的name为“zygote”的为主模式,name为“zygote_secondary”为辅模式。

到此为止,AMS进程试图与Zygote建立连接的代码已经展现完成。


2.Zygote 接收请求

在Socket连接成功并匹配ABI后会返回ZygoteState类型对象,应用进程的启动参数会写入ZygoteState中,这样Zygote进程就会收到一个创立新的应用程序的进程请求。我们回到ZygoteInit的main方法中。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String argv[]){    ...    //创立一个Server端的Socket,socketName的值为“zygote”    zygoteServer.registerServerSocket(socketName);    ...    if(startSystemServer){        //启动SystemServer进程        startSystemServer(abiList,socketName,zygoteServer);    }    ...    //等待AMS请求    zygoteServer.runSelectLoop(abiList);        ...}

我们又回到了Android系统启动流程中,当Zygote启动后,会注册一个Server端的Socket,并且调用runSelectLoop方法来等待AMS的请求。下面来看看runSelectLoop方法。
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java:

void runSelectLoop(String abiList){    ...    ArrayList<ZygoteConnection> peers=new ArrayList<ZygoteConnection>();    fds.add(mServerSocket.getFileDescriptor());    peers.add(null);    while(true){        ...        for(int i = pollFds.length - 1; i >= 0; --i){            if((pollFds[i].revents & POLLIN) == 0){                continue;            }                        if(i == 0){                ZygoteConnection newPeer = acceptCommandPeer(abiList);                peers.add(newPeer);                fds.add(newPeer.getFileDesciptor());            }else{                //AMS的请求过来,最终会走到这里                boolean done = peers.get(i).runOnce(this);                if(done){                    peers.remove(i);                    fds.remove(i);                }            }        }    }}

当AMS的请求过来,最终会调用ZygoteConnection的runOnce方法来解决请求数据。
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java:

boolean runOnce(ZygoteServer zygoteServer){    ...    //获取应用程序进程的启动参数    args = readArgumentList();        ...    //对启动参数的封装    parsedArgs = new Argument(args);        ...    //关键代码,Zygote fork出来子进程    pid = Zygote.forkAndSpecialize(parsedArgs.uid,parsedArgs.gid,parsedArgs.gids,parsedArgs.debugFlags,rlimits,parsedArgs.mountExternal,parsedArgs.seInfo,parsedArgs.appDataDir);        try{        //注意:当前代码逻辑运行在新创立的子进程中了        if(pid==0){            //第一步当然是关闭Zygote与AMS通信的Socket,这对于子进程无意义            zygoteServer.closeServerSocket();            IoUtils.closeQuietly(serverPipeFd);            //解决应用程序进程            handleChildProc(parsedArgs,descriptors,childPipeFd,newStderr);            return true;        }else{            ...        }finally{            ...        }    }}

我们可以在代码中看见,最终在ZygoteConnection中的runOnce方法,Zygote 的forkAndSpecialize方法创立了一个子进程,当pid等于0时,证实当前代码逻辑运行于新创立的子进程也就是应用程序进程中了,而后调用了handleChildProc来进行下一步解决。

因为调用关系繁多,这里不做handleChildProc的代码展现了,最后在该方法中,会调用ZygoteInit的zygoteInit方法,如下图所示。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:

public static final void zygoteInit(int targetSdkVersion,String[] argv,ClassLoader classLoader){    ...        RuntimeInit.redirectLogStreams();    RuntimeInit.commonInit();    //Zygote的nativeZygoteInit方法会启动Binder线程池    ZygoteInit.nativeZygoteInit();    //应用程序进程初始化    RuntimeInit.applicationInit(targetSdkVersion,argv,classLoader);}

ZygoteiInit的nativeZygoteInit方法最后会启动Binder线程池,这部分一会再说,先继续探索RuntimeInit的applicationInit方法。

frameworks/base/core/java/com/android/internal/os/RuntimeInit.java:

protected static void applicationInit(int targetSdkVersion,String[] argv,ClassLoader classLoader){    ...    final Arguments args;    //包装参数    args=Arguments(argv);    ...    //args.startClass 就是 android.app.ActivityThread    invokeStaticMain(args.startClass,args.startArgs,classLoader);}...private static void invokeStaticMain(String className,String[] argv,ClassLoader classLoader){    Class<?> cl;    try{        //取得android.app.ActivityThread类        cl = Class.forName(className,true,classLoader);    }catch(ClassNotFoundException ex){        ...    }    Method m;    try{        //获取ActivityThread的main方法        m = cl.getMethod("main",new Class[]{String[].class});    }catch(NoSuchMethodException ex){        ...    }    ...    //又来这套...    throw new Zygote.MethodAndArgsCaller(m,argv);}

在invokeStaticMain方法中,通过反射的方式找到了ActivityThread类以及它的main方法。在最后抛出异常:throw new Zygote.MethodAndArgsCaller(m,arg),该异常会被Zygote的main方法捕获,至于这里为什么采用了抛出异常的方式而不是直接调用ActivityThread的main方法,原理和Zygote解决SystemServer进程是一毛一样。这种抛出异常的解决会清理所有的设置过程需要的堆栈帧,并让ActivityThread的main方法看起来像是应用程序进程的入口方法(其实不是,在main方法调用前已经做过很多的事情了,比方开启Binder线程池等等)。

既然启动SystemServer以及应用程序进程都用到了这种“奇葩”方式,我们来补齐这部分的代码知识。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java:

public static void main(String argv[]){    try{        ...        closeServerSocket();    }catch(MethodAndArgsCaller caller){        //在这里捕获异常,并且调用MethodAndArgsCaller的run方法        caller.run();    }catch(RuntimeException ex){        ...    }}

MethodAndArgsCaller是Zygote的静态内部类。
frameworks/base/core/java/com/android/internal/os/Zygote.java:

public static class MethodAndArgsCaller extends Exception implements Runnable{    private final Method mMethod;    private final String[] mArgs;    public MethodAndArgsCaller(Method method,String[] args){        mMethod=method;        mArgs=args;    }        //Runnable的run    public void run(){        try{            //最终反射调用main方法,由于是静态方法,所以第一个参数是null            mMethod.invoke(null,new Object[]{mArgs});        }catch(IllegalAccessException ex){            ...        }    }}

完事,最终调用ActivityThread的main方法。

三:Binder线程池启动

刚刚提到过,在ZygoteInit中,初始化应用程序进程之前,会调用nativeZygoteInit方法来初始化Binder线程池。很显著,nativeZygoteInit从名字上来看就是一个JNI方法。

private static final native void nativeZygoteInit();

它所对应的函数是com_android_internal_os_ZygoteInit_nativeZygoteInit,如下。
frameworks/base/core/jni/AndroidRuntime.cpp:

const JNINativeMethod method[]={    { "nativeZygoteInit", "()V", (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit }  ,};...static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env,jobject clazz){    //这个gCurRuntime就是AndroidRuntime类型的指针    gCurRuntime->onZygoteInit();}...static AndoridRuntime* gCurRuntime = NULL;...AndroidRuntime:AndroidRuntime(char* argBlockStart,const size_t argBlockLength):mExitWithoutCleanup(false),mArgBlockStart(argBlockStart),mArgBlockLength(argBlockLength){    ...    gCurRuntime = this;}

AppRuntime 继承自 AndroidRuntime,AppRuntime在创立时就会调用AndroidRuntime的构造函数,gCurRuntime就会被初始化,它指向的是AppRuntime。接下来看看onZygoteInit函数,AppRuntime在app_main.cpp中的实现。
frameworks/base/cmds/app_process/app_main.cpp:

virtual void onZygoteInit(){    sp<ProcessState> proc = ProcessState::self();    proc->startThreadPoll();}

最后调用了ProcessState的startThreadPoll函数来启动线程池。
frameworks/native/libs/binder/ProcessState.cpp:

AutoMutex _l(mLock);//确保Binder线程池只会被启动一次if(!mThreadPollStarted){    mThreadPollStarted = true;    //创立线程池中的第一个线程,也就是该线程池的主线程    spawnPolledThread(true);}...void ProcessState::spawnPooledThread(bool isMain){    if(mThreadPollStarted){        String8 name = makeBinderThreadName();        ...        sp<Thread> t = new PollThread(isMain);        //调用run方法来启动新线程        t->run(name.string())    }}...class PollThread:public Thread{    ...    protected:virtual bool threadLoop(){        IPCThreadState::self()->joinThreadPoll(mIsMain);        return false;    }    const bool mIsMain;};

在最后,调用了IPCThreadState的joinThreadPool函数,将当前线程注册到BInder驱动程序中,这样我们创立的线程就加入了Binder线程池中,新创立的应用程序进程就支持Binder间的通信了。我们只要要创立当前进程的Binder对象,并将它注册到ServiceManager中即可以实现Binder进程间通信。

四:消息循环创立

在Zygote创立完毕应用程序进程,会通过抛异常的方式启动ActivityThread的main方式,然后ActivityThread在main方法中,会开启消息循环,也就是Looper。

fragmeworks/base/core/java/android/app/ActivityThread.java

public static void main(String[] args){    //创立主线程Looper    Looper.prepareMainLooper();        ...        //Looper开始工作    Looper.loop();}

这也就是为什么,我们在主线程中,可以不用调用Looper的prepare方法,但是依然可以使用Handler的起因了,ActivityThread已经帮我们在主线程做了这些事情。

对于Handler、Looper、MessageQueue的关系,感兴趣的童鞋可以参考:传送门

结尾

整个Android应用进程启动过程详情完毕,内容不多但十分重要。开发人员理解自己所开发的应用的进程是如何创立的是十分必要的。

本文大量参考《Android 进阶解密》一书,同时建议对Android底层有兴趣的童鞋搞一本看看,里面讲解的必然比本文精辟不少。

本文纯手打,欢迎各位点亮爱心,给个小小的赞以资鼓励,谢谢

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Android 应用进程启动过程

发表回复