美文网首页
从启动一个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开始聊聊

    简述 我们知道Android系统已经为我们开发者模糊了进程的概念,我们甚至感受不到进程的存在,但是如果要深入了解A...

  • Android-App的启动流程

    App启动流程 app的启动是从main()方法开始的 1、Application的启动 ActivityThre...

  • iOS底层探索30、启动优化分析

    引言 APP 启动,对用户而言,是从点击 APP 开始,到看到 APP 首页展现的过程。 冷启动:针对APP,内存...

  • iOS App 启动都干了哪些事儿

    App 启动我们指的是从用户点击 App 开始,到用户看到第一个界面这个阶段。总结来说,App 的启动主要包括三个...

  • iOS APP 启动优化

    App 的启动时间,指的是从用户点击 App 开始,到用户看到第一个界面之间的时间。总结来说,App 的启动主要包...

  • 【iOS-性能优化二】启动优化

    APP的启动可以分为两种: 冷启动:从0开始启动APP 热启动:APP已经在内存中,在后台存活着,再次点图片 AP...

  • 02-App启动速度优化与监控

    一般而言,App的启动时间,指的是从用户点击App开始,到用户看到第一个界面之间的时间。总结来说,App的启动主要...

  • APP的启动优化

    一般而言,APP的启动时间,是从用户点击APP开始,到用户看到第一个界面之间的时间,总的来说,APP的启动主要包括...

  • iOS 启动优化①之App启动流程

    App 启动时都干了些什么事儿? 一般而言,App 的启动过程,指的是从用户点击 App 开始,到用户看到第一个界...

  • iOS面试-启动优化

    APP启动 APP的启动方式 冷启动(Cold Launch):从零开始启动APP 热启动(Warm Launch...

网友评论

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

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