Android系统源码分析--Process启动过程

因为四大组件的启动都涉及到进程的启动,所以咱们这章先讲一下进程启动流程,而后再讲四大组件的启动流程。java

基础知识

Android应用程序框架层建立的应用程序进程具备两个特色,一是进程的入口函数是ActivityThread.main,二是进程自然支持Binder进程间通讯机制;这两个特色都是在进程的初始化过程当中实现的。(引用自老罗安卓之旅-Android应用程序进程启动过程的源代码分析android

进程按照重要性能够分为下面五类:微信

  • 前台进程(Foreground process)
  • 可见进程(Visible process)
  • 服务进程(Service process)
  • 后台进程(Background process)
  • 空进程(Empty process)

进程启动流程

AMS(ActivityMagagerService)启动进程是从其成员函数startProcessLocked开始调用Process.start方法开始的。咱们先看一下进程启动的时序图:app

1. Process.start方法:

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 {
        // 请求Zygote进程建立一个应用进程
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
     } catch (ZygoteStartFailedEx ex) {
        Log.e(LOG_TAG,
                "Starting VM process through Zygote failed");
        throw new RuntimeException(
                "Starting VM process through Zygote failed", ex);
     }
}复制代码

注意:传入的第一个参数是“android.app.ActivityThread”,这是进程初始化要加载的类,这个类加载到进程以后,就会把这个类的静态成员方法main做为进程的入口。而后调用startViaZygote方法。框架

2. startViaZygote方法:

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中
            ...

            // 保存id到argsForZygote中
            ...

            // 保存其余信息到argsForZygote中
            ...

            // 请求Zygote进程建立这个应用进程
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }复制代码

这个方法主要是保存信息到argsForZygote中,而后调用openZygoteSocketIfNeeded,而后根据返回的值调用zygoteSendArgsAndGetResult方法,首先先看openZygoteSocketIfNeeded方法。socket

3. openZygoteSocketIfNeeded方法:

private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                // 经过调用ZygoteState.connect方法建立LocalSocket对象,以便将相应参数传入Zygote进程
                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
        }

        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }

        // The primary zygote didn't match. Try the secondary.
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            try {
                // 经过调用ZygoteState.connect方法建立LocalSocket对象,以便将相应参数传入Zygote进程
                secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
        }

        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }

        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }复制代码

经过ZygoteState.connect放建立primaryZygoteState对象,若是第一次建立不成功,建立第二次。connect方法代码以下:ide

4. ZygoteState.connect方法:

public static ZygoteState connect(String socketAddress) throws IOException {
            DataInputStream zygoteInputStream = null;
            BufferedWriter zygoteWriter = null;
            // 这个Socket由ZygoteInit.java文件中的ZygoteInit类在runSelectLoopMode函数侦听的。
            final LocalSocket zygoteSocket = new LocalSocket();

            try {
                // 开始创建链接,在链接过程当中,LocalSocket对象zygoteSocket会在/dev/socket目录下找到
                // 一个对应的zygote文件,而后将它与本身绑定起来,这就至关于与Zygote进程中的名称为“zygote”
                // 的Socket创建了链接
                zygoteSocket.connect(new LocalSocketAddress(socketAddress,
                        LocalSocketAddress.Namespace.RESERVED));

                // 链接成功之后,首先获取LocalSocket对象zygoteSocket的一个输入流,而且保存在
                // zygoteInputStream中,以便得到Zygote进程发送过来的通讯数据
                zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

                // 又获得LocalSocket对象zygoteSocket的一个输入流,而且保存在zygoteWriter中,以便
                // 能够向Zygote进程发送通讯数据
                zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                        zygoteSocket.getOutputStream()), 256);
            } catch (IOException ex) {
                ...
            }

            String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
            Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);

            // 建立的LocalSocket对象zygoteSocket会保存在ZygoteState中
            return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                    Arrays.asList(abiListString.split(",")));
        }复制代码

首先建立一个LocalSocket对象,这个LocalSocket对象是在ZygoteInit中的runSelectLoop函数进行监听的。而后经过connect方法而且传入链接地址链接该Socket,链接之后会获取输入流DataInputStream,以便得到Zygote进程发送过来的通讯数据,而后又获取BufferedWriter输入流,以便向Zygote进程发送通讯数据。最后会返回一个ZygoteState对象。下面咱们看一下LocalSocket.connect方法。函数

5. LocalSocket.connect方法:

public void connect(LocalSocketAddress endpoint) throws IOException {
        synchronized (this) {
            if (isConnected) {
                throw new IOException("already connected");
            }

            implCreateIfNeeded();
            impl.connect(endpoint, 0);
            isConnected = true;
            isBound = true;
        }
    }复制代码

若是已经链接,抛出异常,由于链接完成后,会关闭链接,使用时在打开链接。最后调用native方法链接socket,而且改变链接标签。oop

6. 回到第二步,调用完openZygoteSocketIfNeeded返回参数ZygoteState传入到zygoteSendArgsAndGetResult方法中:

private static ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx {
        try {
            // Throw early if any of the arguments are malformed. This means we can
            // avoid writing a partial response to the zygote.
            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()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }

            writer.flush();
            // Zygote进程接收到这些数据以后,就会建立一个新的应用程序进程,而且将这个新建立的应用程序进程
            // 的PID返回给Activity管理服务AMS

            // Should there be a timeout on this?
            ProcessStartResult result = new ProcessStartResult();

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }复制代码

这方法经过Socket流的方式将启动进程的信息发送出去,从步骤4可知,这个Socket的监听是ZygoteInit类中的runSelectLoop方法,咱们接着看这个方法。布局

7. ZygoteInit.runSelectLoop方法:

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

        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 {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            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 {
                    boolean done = peers.get(i).runOnce();
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }复制代码

数据经过Socket发送之后,Zygote进程接收到后会调用peers.get(i).runOnce()方法。这个peers.get(i)是获取ZygoteConnection对象,表示一个Socket链接,而后调用它的runOnce方法。

8. ZygoteConnection.runOnce方法:

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try {
            // 得到建立应用程序进程须要的启动参数,而且保存在一个Arguments对象parsedArgs中
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }

        ...

        /** the stderr of the most recent request, if avail */
        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 {
            parsedArgs = new Arguments(args);

            if (parsedArgs.abiListQuery) {
                return handleAbiListQuery();
            }

            ...

            // 调用forkAndSpecialize方法来建立这个应用程序进程,最终经过函数fork在当前进程中建立一个子进程,
            // 所以,当它的返回值等于0时,就表示是在新建立的子进程中执行的,这时候ZygoteConnection类就会调用
            // 成员函数handleChildProc来启动这个子进程
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } catch (ErrnoException ex) {
            ...
        } catch (IllegalArgumentException ex) {
            ...
        } catch (ZygoteSecurityException ex) {
            ...
        }

        try {
            if (pid == 0) {
                ...
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                return true;
            } else {
                ...
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            ...
        }
    }复制代码

首先经过Zygote.forkAndSpecialize方法来建立一个新的进程,而且返回其pid。由于咱们在分心新建进程,所以咱们只分析pid为0的状况,pid为0时会调用handleChildProc方法,

9. handleChildProc方法:

private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller {
        ...

        // End of the postFork event.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);
        } else {
            // 初始化运行库以及启动一个Binder线程池
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }复制代码

因为咱们以前加入参数是没有parsedArgs.invokeWith这个参数,所以这里是null,所以会走else里面的代码,执行RuntimeInit.zygoteInit方法。

10. RuntimeInit.zygoteInit方法:

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
        redirectLogStreams();

        // 首先调用下面函数来设置新建立的应用程序进程的时区和键盘布局等通用信息
        commonInit();
        // 而后调用下面Native函数在新建立的应用程序进程中启动一个Binder线程池
        nativeZygoteInit();
        applicationInit(targetSdkVersion, argv, classLoader);
    }复制代码

首先调用nativeZygoteInit函数,这是一个native函数,函数的目的是在新建立的应用程序进程中启动一个Binder线程池而后进行进程间通讯。而后调用applicationInit函数

11. applicationInit函数:

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
        ...

        // Remaining arguments are passed to the start class's static main
        // 咱们知道AMS指定了新建立的应用程序进程的入口函数为ActivityThread类的静态成员函数main。实际是
        // 经过下面方法进入到ActivityThread类的静态成员函数main中的
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }复制代码

咱们在前面讲过args.startClass传入进来的是"android.app.ActivityThread",表示要执行"android.app.ActivityThread"的main函数。

12. invokeStaticMain函数:

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            ...
        }

        Method m;
        try {
            // 获取它的静态成员函数main,而且保存在Method对象m中
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            ...
        } catch (SecurityException ex) {
            ...
        }

        ...

        /* * This throw gets caught in ZygoteInit.main(), which responds * by invoking the exception's run() method. This arrangement * clears up all the stack frames that were required in setting * up the process. * 将这个Method对象封装在一个MethodAndArgsCaller对象中,而且将这个MethodAndArgsCaller对象做为 * 一个异常对象抛出来给当前应用程序处理 */
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
        /** * 引用自Android系统源代码情景分析中的Android进程启动分析一文 * 新建立的应用程序进程复制了Zygote进程的地址空间,所以,当前新建立的应用程序进程的调用栈与Zygote * 进程的调用堆栈是一致的。Zygote进程最开始执行的是应用程序app_process的入口函数main,接着再调用 * ZygoteInit类的静态成员函数main,最后进入到ZygoteInit类的静态成员函数runSelectLoopMode来循环 * 等待Activity管理服务AMS发送过来的建立新的应用进程的请求。当Zygote进程收到AMS发送过来的建立新的 * 应用程序进程的请求以后,它就会建立一个新的应用程序进程,而且让这个新建立的应用程序进程沿着 * ZygoteInit类的静态函数runSelectLoopModel一直执行到RuntimeInit类的静态成员函数 * invokeStaticMain。所以,当RuntimeInit类的静态成员函数invokeStaticMain抛出一个类型为 * MethodAndArgsCaller的常时,系统就会沿着这个调用过程日后找到一个适合的代码块来捕获它。 * 因为ZygoteInit函数main捕获了类型为MethodAndArgsCaller的异常,所以,接下来它就会被调用,以便 * 能够处理这里抛出的一个MethodAndArgsCaller异常。所以,抛出这个异常后,会执行ZygoteInit中main * 函数中的catch来捕获异常。 * */
    }复制代码

这个就是经过类加载器加载ActivityThread,而后调用起main方法。而后抛出异常,经过ZygoteInit中main函数中的catch来捕获异常。

13. ZygoteInit.main函数:

public static void main(String argv[]) {
        ...
        } catch (MethodAndArgsCaller caller) {
            // 捕获MethodAndArgsCaller异常之后会调用MethodAndArgsCaller的run函数
            // ActivityThread.main
            caller.run();
        } catch (Throwable ex) {
            ...
        }
    }复制代码

经过步骤12可知抛出的异常是MethodAndArgsCaller异常,所以会执行caller.run方法。

14. MethodAndArgsCaller.run:

/** * 注释来自Android系统源代码情景分析 * 这里开始调用ActivityThread.main方法,为何要绕这么远呢,前面提到,AMS请求Zygote进程建立的应用 * 程序进程的入口函数为ActivityThread的main函数,可是因为新建立的应用程序进程一开始就须要再内部初始 * 化运行时库,以及启动Binder线程池,所以,ActivityThread的main函数被调用时,新建立的应用程序进程 * 实际上已经执行了至关多的代码,为了使得西建立的应用程序的进程以为它的入口函数就是ActivityThread类 * 的main函数,系统就不能直接调用,而是抛出异常回到ZygoteInit的main函数中,而后间接调用它,这样就 * 能够巧妙的利用Java语言的异常处理来清理它前面调用的堆栈了 */
        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);
            }
        }复制代码

经过mMethod.invoke方法调用ActivityThread的main方法。

15. ActivityThread.mian方法:

/** * 启动新的进程时调用Process的start方法会最终调用改函数 * 启动新的进程主要作了两件事: * 1.在进程中建立了一个ActivityThread对象,并调用了它的成员函数attach向AMS发送一个启动完成的通知 * 2.调用Looper类的静态成员函数prepareMainLooper建立一个消息循环,而且在向AMS发送启动完成通知后, * 使得当前进程进入到这个消息循环中 * * @param args */
    public static void main(String[] args) {
        ...

        // 建立looper
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        // 传入false表示非系统进程启动
        thread.attach(false);

        if (sMainThreadHandler == null) {
            // 获取主线程的Handler
            sMainThreadHandler = thread.getHandler();
        }

        ...

        // 开始无限循环
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }复制代码

这里主要是建立该线程的looper,而后建立ActivityThread对象,而后进入消息循环。而后咱们就能够启动Activity或者Service了。

Android开发群:192508518

微信公众帐号:Code-MX

注:本文原创,转载请注明出处,多谢。

相关文章
相关标签/搜索