美文网首页
从启动一个app开始聊聊

从启动一个app开始聊聊

作者: 我叫王菜鸟 | 来源:发表于2017-08-27 20:50 被阅读0次

    简述

    我们知道Android系统已经为我们开发者模糊了进程的概念,我们甚至感受不到进程的存在,但是如果要深入了解Android系统就需要了解进程在Android中如何创建以及模糊的,我们今天的主题就是来探讨从APP的角度,进程是如何创建的。

    概念储备

    1.进程&线程

    官方解释

    • 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
    • 线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。

    翻译解释

    可能上面的文字,我们并不知道说的什么,那下面我们就把这些翻译一下:

    • 进程就是计算机独立分配资源的最小单位,资源就是那些变量乱七八糟使用的内存啊,cpu的调度呀等。
    • 线程就是在进程中再次分出来相对独立可调度执行的单位,也就是一个进程内部可以包含多个线程,线程可以独立调度cpu的分配。

    2.涉及Android中的进程&线程

    • SystemServer进程
    • Zygote进程
    进程启动.png

    大概过程是:

    app进程如果从桌面启动的话,发起的是Lacuncher所在进程,然后通过Binder调用到AMS,通过AMS的调用最后使用socket给zygote进程,zygote中有个循环,一直在读取socket的链接资源当读取到要创建进程的时候,则会fork()子进程,完了就会在新的进程中去创建一些Android系统的环境,所以最后走到ActivityThread.main()

    发起环节

    发起环节,主要是由于发起进程方,通过四大组件拉起进程方式是通过Binder调用AMS中,AMS最后会通过Process.java和Zygote通信创建进程,所以直接看Process.java

    1.1 Process.start()

    Process.java

    public static final 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[] zygoteArgs) {
        try {
             //[1.2]
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            throw new RuntimeException("");
        }
    }
    

    1.2 Process.startViaZygote()

    Process.java

    private static 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[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {
            ArrayList<String> argsForZygote = new ArrayList<String>();
    
            argsForZygote.add("--runtime-args");
            argsForZygote.add("--setuid=" + uid);
            argsForZygote.add("--setgid=" + gid);
            argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
    
            if (niceName != null) {
                argsForZygote.add("--nice-name=" + niceName);
            }
            if (appDataDir != null) {
                argsForZygote.add("--app-data-dir=" + appDataDir);
            }
            argsForZygote.add(processClass);
    
            if (extraArgs != null) {
                for (String arg : extraArgs) {
                    argsForZygote.add(arg);
                }
            }
             //[1.3][1.2]
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }
    

    1.2 Process.openZygoteSocketIfNeeded()

    Process.java

    private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                //向主zygote发起connect()操作
                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
            } catch (IOException ioe) {
                ...
            }
        }
    
        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }
    
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            //当主zygote没能匹配成功,则采用第二个zygote,发起connect()操作
            secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
        }
    
        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }
        ...
    }
    

    这里我们已经看出来zygoteSendArgsAndGetResult()这个方法的预谋,这个方法主要就是进行socket链接操作并且获取流。

    1.3 Process.zygoteSendArgsAndGetResult()

    Process.java

    private static ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;
    
            writer.write(Integer.toString(args.size()));
            writer.newLine();
    
            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                if (arg.indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx(
                            "embedded newlines not allowed");
                }
                writer.write(arg);
                writer.newLine();
            }
    
            writer.flush();
    
            ProcessStartResult result = new ProcessStartResult();
            //等待socket服务端(即zygote)返回新创建的进程pid;
            result.pid = inputStream.readInt();
            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            result.usingWrapper = inputStream.readBoolean();
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }
    

    看到这里已经出现了socket对流的操作,读和写,具体就是将数据封装到集合中,然后将几个一个个写入流中,最后阻塞进行等待。其实这里谷歌工程师也意识到有可能创建进程一直卡死到zygote哪里,并写入读的流,所以他们给这里说可能会加入时间判断。

    这里还需注意的事情有:

    • ProcessStartResult对象
    • zygoteState:这个是通过1.2返回的链接对象,将socket链接的信息封装在zygoteState这个对象中

    创建环节

    这里是通过Zygote进程进行创建的,Zygote进程来自于init进程,init进程这里不说,总之init进程创建Zygote进程之后就进入到了java世界,这个java世界进行创建进程了,但是怎么给空荡荡的进程装配Android环境呢?最后一步就是调用ActivityThread.main()方法,而且形式很特殊,是通过抛出异常的形式,这样目的就清理调用栈,因为那些创建过程中的调用栈也没有用,只需要传递最后那些调用栈过程中得到的结果,并将结果作为参数封装成异常的形式进行抛出。是不是很巧秒啊,哈哈。

    1.1 ZygoteInit.main()

    ZygoteInit.java

    public static void main(String argv[]) {
        try {
            runSelectLoop(abiList); //[1.2]
            ....
        } catch (MethodAndArgsCaller caller) {
            caller.run(); //
        } catch (RuntimeException ex) {
            closeServerSocket();
            throw ex;
        }
    }
    

    1.2 ZygoteInit.runSelectLoop()

    ZygoteInit.java

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        //sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
    
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                 //处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                ...
            }
    
            for (int i = pollFds.length - 1; i >= 0; --i) {
                //当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
                // 否则进入continue,跳出本次循环。
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                if (i == 0) {
                    //即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;
                    // 则创建ZygoteConnection对象,并添加到fds。//[1.3]
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor()); //添加到fds.
                } else {
                    //i>0,则代表通过socket接收来自对端的数据,并执行相应操作[2.1]
                    boolean done = peers.get(i).runOnce();
                    if (done) {
                        peers.remove(i);
                        fds.remove(i); //处理完则从fds中移除该文件描述符
                    }
                }
            }
        }
    }
    

    我们看到这里有个大的死循环,一般死循环中肯定有阻塞时间,系统没事不可能闲着让他一直占有cpu干一写没有意义的事情,这里我们回想Process.java类中的一个方法,openZygoteSocketIfNeeded()来跟zygote进程建立链接,zygote进程收到客户端链接的请求之后执行acceptCommandPeer()因为链接并不需要数据,所以i==0,然后在创建ZygoteConnection对象,并添加到fds数组中。

    我们在看看这块逻辑:

    1.Process.java中通过 ZygoteState.connect(ZYGOTE_SOCKET);发起请求
    2.ZygoteInit.runSelectLoop()在Os.poll(pollFds, -1);中收到请求
    3. for (int i = pollFds.length - 1; i >= 0; --i) 此时i = pollFds.length - 1,由于pollFds.length=1,因为链接并不产生数据,所以不增加事件个数所以i==0
    4. ZygoteConnection newPeer = acceptCommandPeer(abiList);所以创建链接并添加
    5.  peers.get(i).runOnce();当数据来的时候调用ZygoteConnection.runOnce()
    

    我们不妨看看Os.poll();的说明:

    poll() performs a similar task to select(2): it waits for one of a set of file descriptors to become ready to perform I/O.
    
    The set of file descriptors to be monitored is specified in the fds
    argument, which is an array of structures of the following form:
    
       struct pollfd {
           int   fd;         /* file descriptor */
           short events;     /* requested events */
           short revents;    /* returned events */
       };
    
    The caller should specify the number of items in the fds array in
    nfds.
    nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;
    timeout:是poll函数调用阻塞的时间,单位:毫秒;
    返回值:
    >0:数组fds中准备好读、写或出错状态的那些socket描述符的总数量;
    ==0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒;
    换句话说,如果所检测的socket描述符上没有任何事件发生的话,那么poll()函数会阻塞timeout所指定的毫秒时间长度之后返回,
    如果timeout==0,那么poll() 函数立即返回而不阻塞
    如果timeout==INFTIM,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回
    如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;
    

    poll()在等待执行IO操作。和select函数差不多,后来Linux内核升级就慢慢的用epoll代替了。

    1.3 ZygoteInit.acceptCommandPeer()

    ZygoteInit.java

    private static ZygoteConnection acceptCommandPeer(String abiList) {
        try {
            return new ZygoteConnection(sServerSocket.accept(), abiList);
        } catch (IOException ex) {
            ...
        }
    }
    

    将客户端发送过来的connect()进行封装。

    这里我们可能会好奇sServerSocket.accept()方法就可以得到Process.java那边的socket。怎么就是同一个了。
    我们看这段证据:

    我们在ZygoteInit.main()中这样执行
    String socketName = "zygote";
    registerZygoteSocket(socketName);
    int fileDesc;
    final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;//"ANDROID_SOCKET_";
    String env = System.getenv(fullSocketName);
    fileDesc = Integer.parseInt(env);
    FileDescriptor fd = new FileDescriptor();
    fd.setInt$(fileDesc);
    sServerSocket = new LocalServerSocket(fd);
    

    这段代码就是将名称zygote设置成sServerSocket

    我们再来看看Process.java那边

    primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);//public static final String ZYGOTE_SOCKET = "zygote";
    final LocalSocket zygoteSocket = new LocalSocket();//创建type为2
    zygoteSocket.connect(new LocalSocketAddress(socketAddress,LocalSocketAddress.Namespace.RESERVED));
    impl.connect(endpoint, 0);//将LocalSocketAddress传如connect中
    osType = OsConstants.SOCK_STREAM;
    fd = Os.socket(OsConstants.AF_UNIX, osType, 0);//其中fd来自与创建的type为2
    
    connectLocal(fd, address.getName(), address.getNamespace().getId());//fd=2
    private native void connectLocal(FileDescriptor fd, String name,int namespace) throws IOException;
    

    native层此时已经知道要找的fd,name,namespace那就对应到ZygoteInit中去。

    2.1 ZygoteInit.runOnce()

    ZygoteInit.java

    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
    
        try {
            //读取socket客户端发送过来的参数列表
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            closeSocket();
            return true;
        }
    
        PrintStream newStderr = null;
        if (descriptors != null && descriptors.length >= 3) {
            newStderr = new PrintStream(new FileOutputStream(descriptors[2]));
        }
    
        int pid = -1;
        FileDescriptor childPipeFd = null;
        FileDescriptor serverPipeFd = null;
    
        try {
            //将socket客户端传递过来的参数,另封装成Arguments对象格式
            parsedArgs = new Arguments(args);
            ...
    
            int [] fdsToClose = { -1, -1 };
            FileDescriptor fd = mSocket.getFileDescriptor();
            if (fd != null) {
                fdsToClose[0] = fd.getInt$();
            }
    
            fd = ZygoteInit.getServerSocketFileDescriptor();
            if (fd != null) {
                fdsToClose[1] = fd.getInt$();
            }
            fd = null;
            //[3.1]
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } catch (Exception e) {
            ...
        }
    
        try {
            if (pid == 0) {
                //子进程执行
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                //[2.2]
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                // 不应到达此处,子进程预期的是抛出异常ZygoteInit.MethodAndArgsCaller或者执行exec().
                return true;
            } else {
                //父进程执行
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
    

    3.1 Zygote.forkAndSpecialize()

    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          String instructionSet, String appDataDir) {
        VM_HOOKS.preFork(); //停止四个Deamon子线程,等待所有子线程结束之后完成gc堆的初始化
        //[4.1]
        int pid = nativeForkAndSpecialize(
                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  instructionSet, appDataDir); 
        ...
        //VM_HOOKS.postForkCommon的主要功能是在fork新进程后,
        //启动Zygote的4个Daemon线程,java堆整理,引用队列,以及析构线程。
        VM_HOOKS.postForkCommon(); 
        return pid;
    }
    

    4.1 com_android_internal_os_Zygote.forkAndSpecialize()

    static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
        JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
        jint debug_flags, jobjectArray rlimits,
        jint mount_external, jstring se_info, jstring se_name,
        jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
        // 将CAP_WAKE_ALARM赋予蓝牙进程
        jlong capabilities = 0;
        if (uid == AID_BLUETOOTH) {
            capabilities |= (1LL << CAP_WAKE_ALARM);
        }
        //4.2
        return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
                rlimits, capabilities, capabilities, mount_external, se_info,
                se_name, false, fdsToClose, instructionSet, appDataDir);
    }
    

    4.2 com_android_internal_os_Zygote.ForkAndSpecializeCommon()

    static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
                                         jint debug_flags, jobjectArray javaRlimits,
                                         jlong permittedCapabilities, jlong effectiveCapabilities,
                                         jint mount_external,
                                         jstring java_se_info, jstring java_se_name,
                                         bool is_system_server, jintArray fdsToClose,
                                         jstring instructionSet, jstring dataDir) {
      //设置子进程的signal信号处理函数
      SetSigChldHandler();
      //fork子进程 
      pid_t pid = fork();
      if (pid == 0) { //进入子进程
        DetachDescriptors(env, fdsToClose); //关闭并清除文件描述符
    
        if (!is_system_server) {
            //对于非system_server子进程,则创建进程组
            int rc = createProcessGroup(uid, getpid());
        }
        SetGids(env, javaGids); //设置设置group
        SetRLimits(env, javaRlimits); //设置资源limit
    
        int rc = setresgid(gid, gid, gid);
        rc = setresuid(uid, uid, uid);
    
        SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
        SetSchedulerPolicy(env); //设置调度策略
    
         //selinux上下文
        rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
    
        if (se_info_c_str == NULL && is_system_server) {
          se_name_c_str = "system_server";
        }
        if (se_info_c_str != NULL) {
          SetThreadName(se_name_c_str); //设置线程名为system_server,方便调试
        }
        //在Zygote子进程中,设置信号SIGCHLD的处理器恢复为默认行为
        UnsetSigChldHandler();
        //等价于调用zygote.callPostForkChildHooks() [3.2]
        env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
                                  is_system_server ? NULL : instructionSet);
        ...
    
      } else if (pid > 0) {
        //进入父进程,即Zygote进程
      }
      return pid;
    }
    

    这里必须小结一下:

    1. 设置新创的进程signal处理函数,这个处理函数以后会用到,只不过不是本章重点
    2. 进入子进程关闭文件描述
    3. 创建进程组
    4. 设置group
    5. 设置调度策略

    也就是做一些底层的初始化工作,还有信号函数哦,别忘了

    3.2 Zygote.callPostForkChildHooks()

    private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer,
            String instructionSet) {
        //调用ZygoteHooks.postForkChild()
        VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
    }
    
    public void postForkChild(int debugFlags, String instructionSet) {
        nativePostForkChild(token, debugFlags, instructionSet);
        Math.setRandomSeedInternal(System.currentTimeMillis());
    }
    

    我们这里就不看native层了,native层做的事情就是

    • 设置新进程的主线程id
    • 设置java堆处理线程池
    • 重置gc性能数据
    • 设置信号函数

    这里小结下 ZygoteInit.runOnce()中调用forkAndSpecialize()方法做的事情:

    • 停止Zygote的4个Daemon子线程的运行,初始化gc堆;
    • 调用fork()创建新进程,设置新进程的主线程id,重置gc性能数据,设置信号处理函数等功能。
    • 启动4个Deamon子线程。

    2.2 ZygoteConnection.handleChildProc()

    ZygoteConnection.java

    private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
    
        //关闭Zygote的socket两端的连接
        closeSocket();
        ZygoteInit.closeServerSocket();
    
        if (descriptors != null) {
            try {
                Os.dup2(descriptors[0], STDIN_FILENO);
                Os.dup2(descriptors[1], STDOUT_FILENO);
                Os.dup2(descriptors[2], STDERR_FILENO);
                for (FileDescriptor fd: descriptors) {
                    IoUtils.closeQuietly(fd);
                }
                newStderr = System.err;
            } catch (ErrnoException ex) {
                Log.e(TAG, "Error reopening stdio", ex);
            }
        }
    
        if (parsedArgs.niceName != null) {
            //设置进程名
            Process.setArgV0(parsedArgs.niceName);
        }
    
        if (parsedArgs.invokeWith != null) {
            //于检测进程内存泄露或溢出时
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);
        } else {
            //执行目标类的main()方法[5.1]
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null);
        }
    }
    
    

    5.1 RuntimeInit.zygoteInit()

    RuntimeInit.java

    public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
    
        redirectLogStreams(); //重定向log输出
    
        commonInit(); // 通用的一些初始化[5.2]]
        nativeZygoteInit(); // zygote初始化 【见流程6.1】
        applicationInit(targetSdkVersion, argv, classLoader); // 应用初始化[5.4]
    }
    

    5.2 RuntimeInit.commonInit()

    private static final void commonInit() {
        // 设置默认的未捕捉异常处理方法
        Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
    
        // 设置市区,中国时区为"Asia/Shanghai"
        TimezoneGetter.setInstance(new TimezoneGetter() {
            public String getId() {
                return SystemProperties.get("persist.sys.timezone");
            }
        });
        TimeZone.setDefault(null);
    
        //重置log配置
        LogManager.getLogManager().reset();
        new AndroidConfig();
    
        // 设置默认的HTTP User-agent格式,用于 HttpURLConnection。
        String userAgent = getDefaultUserAgent();
        System.setProperty("http.agent", userAgent);
    
        // 设置socket的tag,用于网络流量统计
        NetworkManagementSocketTagger.install();
    }
    
    • 看这里看这里,这里设置了默认异常捕获的方法
    • 设置了时区
    • 重置了log配置
    • 设置默认http
    • 设置网络流量统计

    6.1 AndroidRuntime.cpp

    AndroidRuntime.cpp

    static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
    {
        //此处的gCurRuntime为AppRuntime,是在AndroidRuntime.cpp中定义的
        gCurRuntime->onZygoteInit();
    }
    
    virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        proc->startThreadPool(); //启动新binder线程
    }
    

    这里目的是启动一个Binder线程

    5.4 RuntimeInit.applicationInit()

    private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        //true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用
        nativeSetExitWithoutCleanup(true);
    
        //设置虚拟机的内存利用率参数值为0.75
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    
        final Arguments args;
        try {
            args = new Arguments(argv); //解析参数
        } catch (IllegalArgumentException ex) {
            return;
        }
    
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    
        //调用startClass的static方法 main() [5.5]//args.startClass为”android.app.ActivityThread”
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }
    

    5.5 RuntimeInit.invokeStaticMain()

    RuntimeInit.java

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl = Class.forName(className, true, classLoader);
    
        Method m = cl.getMethod("main", new Class[] { String[].class });
    
        int modifiers = m.getModifiers();
        ...
    
        //通过抛出异常,回到ZygoteInit.main()。这样做好处是能清空栈帧,提高栈帧利用率。【见流程16】
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }
    

    我的天,终于抛出异常了,这个异常一下回到解放前:

    public static void main(String argv[]) {
        try {
            runSelectLoop(abiList); //[1.2]
            ....
        } catch (MethodAndArgsCaller caller) {
            caller.run(); //就是这里
        } catch (RuntimeException ex) {
            closeServerSocket();
            throw ex;
        }
    }
    

    继续走起:

    MethodAndArgsCaller.run()

    public static class MethodAndArgsCaller extends Exception
            implements Runnable {
    
        public void run() {
            try {
                //根据传递过来的参数,此处反射调用ActivityThread.main()方法
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw new RuntimeException(ex);
            }
        }
    }
    

    我们不容易啊,终于通过runSelectLoop中创建的子进程抛出给ZygoteInit.java了,但是这里已经是复制过父进程的Zygote了,所以一些资源也过来了,不一样就是要初始化一些子进程的资源。我们在来回顾一下吧。

    ZygoteInit.main//进入到ZygoteInit.java由于init进程导致
        ZygoteInit.runSelectLoop()
            ZygoteConnection.runOnce()//读取参数并调用下面方法
                Zygote.forkAndSpecialize()//初始化初始化虚拟机那些工作,然后创建子进程
                    Zygote.nativeForkAndSpecialize()
                        com_android_internal_os_Zygote.ForkAndSpecializeCommon()//设置子进程signal,创建进程组,设置掉副方法等
                            pid = fork();
                            
                Zygote.handleChildProc()//设置进程名
                    RuntimeInit.zygoteInit()
                        commonInit();//通用的一些初始化,时区,异常处理办法
                            Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
                        nativeZygoteInit();zygote初始化
                            onZygoteInit();
                                sp<ProcessState> proc = ProcessState::self();
                                proc->startThreadPool(); //启动新binder线程
                        applicationInit();应用初始化
                            invokeStaticMain(args.startClass, args.startArgs, classLoader);
                                throw new ZygoteInit.MethodAndArgsCaller(m, argv);
                                    mMethod.invoke(null, new Object[] { mArgs });
                                        ActivityThread.main()//这里进行app进程里面的组件那些初始化拉起来等
                                    
    

    看着这个调用栈,我们就从接收一个空荡荡的进程信号,创建一个空荡荡的进程,然后又一个空荡荡的进程,初始化了一下不空荡荡(gc,binder线程,异常处理,时区)的操作,让进程变得稍微丰富,此时进程具备了Android环境的能力。但是这只是app的开始,四大组件那些还没有用到不算app完全起来。

    app进程启动.png

    相关文章

      网友评论

          本文标题:从启动一个app开始聊聊

          本文链接:https://www.haomeiwen.com/subject/nwyidxtx.html