Android應用程序的進程創建過程


前言

我們知道當startActivity的時候,除了創建Activity相關實體,系統會根據需要是否創建進程,此進程就是指的Linux層面的進程實體;后面會說到,其實創建的過程是fork,意為從父進程“copy”出一個新的進程。此過程必定經歷啟動者、ams、zygote等相互的進程間通信,本文主要梳理ams在此過程的重要環節,涉及虛擬機的繼承、Binder線程池、消息循環是怎么建立的等等,而Activity的啟動細節則放在其他章節另作探討。

步驟

step1 Ams發起請求startProcessLocked

ActivityManagerService.java

直接從Ams中向zygote發起請求的入口開始分析,當然真正的開始是Ams收到其他應用的Binder請求,所以應該在onTransact里面才是真正的開始,待會兒會打出trace看。(這兒一個小細節,源碼中有很多方法帶Locked后綴,說明使用該方法需要加鎖,因為其是非線程安全的)。

            // Start the process.  It will either succeed and return a result containing
            // the PID of the new process, or else throw a RuntimeException.
            boolean isActivityProcess = (entryPoint == null);
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkTime(startTime, "startProcess: asking zygote to start proc");
            Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);
            checkTime(startTime, "startProcess: returned from zygote!");
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

比較重要的是這一段話,調用Process類的start方法,並指定了入口類為ActivityThread。

system    671   641   2348412 179992          0 0000000000 S Binder:641_1

641-671/system_process W:     at android.os.Process.zygoteSendArgsAndGetResult(Process.java:605)
641-671/system_process W:     at android.os.Process.startViaZygote(Process.java:738)
641-671/system_process W:     at android.os.Process.start(Process.java:521)
641-671/system_process W:     at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:4214)
641-671/system_process W:     at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:4069)
641-671/system_process W:     at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3909)
641-671/system_process W:     at com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1441)
641-671/system_process W:     at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2741)
641-671/system_process W:     at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2213)
641-671/system_process W:     at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:1859)
641-671/system_process W:     at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1393)
641-671/system_process W:     at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:1237)
641-671/system_process W:     at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:7393)
641-671/system_process W:     at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:571)
641-671/system_process W:     at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3169)
641-671/system_process W:     at android.os.Binder.execTransact(Binder.java:565)

從如上的trace可以直接看出,在收到startActivity的請求后,執行了對當前Activity的pause操作,然后通過Process.java這個類對Zygote進程發起請求。注意,通過對線程號的觀察可以看到,這一切都在一次binder線程中操作的。

注意Ams與Zygote之間是通過socket連接的,封裝了zygoteState類去做通信相關的任務。從下圖fd的占用可以明確地看到,zygote進程是不使用binder的。

device:/proc/341/fd # ls -l
ls -l
total 0
lrwx------ 1 root root 64 2021-03-16 17:49 0 -> /dev/null
lrwx------ 1 root root 64 2021-03-16 17:49 1 -> /dev/null
lr-x------ 1 root root 64 2021-03-16 17:49 10 -> /system/framework/core-oj.jar
lr-x------ 1 root root 64 2021-03-16 17:49 11 -> /system/framework/core-libart.jar
lr-x------ 1 root root 64 2021-03-16 17:49 12 -> /system/framework/conscrypt.jar
lr-x------ 1 root root 64 2021-03-16 17:49 13 -> /system/framework/okhttp.jar
lr-x------ 1 root root 64 2021-03-16 17:49 14 -> /system/framework/core-junit.jar
lr-x------ 1 root root 64 2021-03-16 17:49 15 -> /system/framework/bouncycastle.jar
lr-x------ 1 root root 64 2021-03-16 17:49 16 -> /system/framework/ext.jar
lr-x------ 1 root root 64 2021-03-16 17:49 17 -> /system/framework/framework.jar
lr-x------ 1 root root 64 2021-03-16 17:49 18 -> /system/framework/telephony-common.jar
lr-x------ 1 root root 64 2021-03-16 17:49 19 -> /system/framework/voip-common.jar
lrwx------ 1 root root 64 2021-03-16 17:49 2 -> /dev/null
lr-x------ 1 root root 64 2021-03-16 17:49 20 -> /system/framework/ims-common.jar
lr-x------ 1 root root 64 2021-03-16 17:49 21 -> /system/framework/apache-xml.jar
lr-x------ 1 root root 64 2021-03-16 17:49 22 -> /system/framework/org.apache.http.legacy.boot.jar
lrwx------ 1 root root 64 2021-03-16 17:49 23 -> socket:[9842]
lr-x------ 1 root root 64 2021-03-16 17:49 24 -> /system/framework/framework-res.apk
lr-x------ 1 root root 64 2021-03-16 17:49 25 -> /dev/urandom
l-wx------ 1 root root 64 2021-03-16 17:49 5 -> /sys/kernel/debug/tracing/trace_marker
lrwx------ 1 root root 64 2021-03-16 17:49 6 -> /dev/null
lrwx------ 1 root root 64 2021-03-16 17:49 7 -> /dev/null
lrwx------ 1 root root 64 2021-03-16 17:49 8 -> /dev/null
lrwx------ 1 root root 64 2021-03-16 17:49 9 -> socket:[9289]

Ams的調用棧到上面就截止了,接下來進入到Zygote進程中。

step2 Zygote收到請求

猜想Zygote進程初始化完成后,一定有個無限循環在等待其他進程的請求,直接定位到代碼。

 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);
                    }
                }
            }
        }
    }

可以看到,當接收到請求后,調用ZygoteConnection類的runOnce來處理。

 boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

        .......省略代碼

        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);

        ......省略代碼

    try {
        /*子進程執行pid==0情況,父進程執行else情況*/
        if (pid == 0) {
            /*子進程*/
            // in child
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

            // should never get here, the child is expected to either
            // throw ZygoteInit.MethodAndArgsCaller or exec().
            return true;
        } else {
            // in parent...pid of < 0 means failure
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            /*Process中的io流監聽的pid等信息都是通過下面的代碼發出去的*/
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

主要玄機是forkAndSpecialize這個方法,能fork出native的子進程,然后再返回到調用的地方;但是會返回兩次,一次是子進程,一次是父進程,這個通過返回值來判斷,和linux的fork方法類似;如果是子進程,那么執行handleChildProc,注意下面的注釋,意味着不會執行到return的語句,也就是上層的selectloop(因為子進程不用管zygote的接受命令循環了,直接去執行app進程的任務了);而父進程會調用handleParentProc后返回。

子進程的返回有個小技巧,是通過拋一個異常達到的,那么回到了哪里?我們再看一下ZygoteInit.java的main方法。

    public static void main(String argv[]) {
        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ...
        try {
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
            RuntimeInit.enableDdms();
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();
            registerZygoteSocket(socketName);
            preload();
            gcAndFinalize();
            // Zygote process unmounts root storage spaces.
            Zygote.nativeUnmountStorageOnInit();
            ...
            Log.i(TAG, "Accepting command socket connections");
            /*這兒調用的runSelectLoop開啟等待循環的*/
            runSelectLoop(abiList);
            
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

是不是看到了熟悉的身影runSelectLoop,所以是Zygote進入java世界后,先進入main方法做了一些准備工作,然后開啟selectLoop進行等待循環,而收到子進程拋出的MethodAndArgsCaller異常后會執行caller.run,這是我們能從調用棧中看到子進程生命的開始,之所以這樣做,還可以通過拋異常的方式清空之前的調用棧,去除一些fork、設置等,看起來app的生命更清爽。如下圖到onCreate的流程。

3199-3199/com.android.myapplication W:     at com.android.myapplication.MainActivity.onCreate(MainActivity.java:42)
3199-3199/com.android.myapplication W:     at android.app.Activity.performCreate(Activity.java:6709)
3199-3199/com.android.myapplication W:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
3199-3199/com.android.myapplication W:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2624)
3199-3199/com.android.myapplication W:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2732)
3199-3199/com.android.myapplication W:     at android.app.ActivityThread.-wrap12(ActivityThread.java)
3199-3199/com.android.myapplication W:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1483)
3199-3199/com.android.myapplication W:     at android.os.Handler.dispatchMessage(Handler.java:102)
3199-3199/com.android.myapplication W:     at android.os.Looper.loop(Looper.java:154)
3199-3199/com.android.myapplication W:     at android.app.ActivityThread.main(ActivityThread.java:6141)
3199-3199/com.android.myapplication W:     at java.lang.reflect.Method.invoke(Native Method)
3199-3199/com.android.myapplication W:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
3199-3199/com.android.myapplication W:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)

哈哈,扯遠了,繼續看一下剛才子進程調用的handleChildProc到底做了什么事兒。

step3 handleChildProc -- 進入子進程的世界

.frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

按照慣例,先看調用棧。

private void handleChildProc(Arguments parsedArgs,
        FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
        throws ZygoteInit.MethodAndArgsCaller {
        
        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.runtimeInit) {
        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    pipeFd, parsedArgs.remainingArgs);
        } else {
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    } else {
       ......省略代碼
    }
}

一開始進來有一些資源回收的工作,比如關閉socket等,因為子進程用不到了,避免占用fd。dup2那三個操作是把原來的標准輸入、標准輸出和錯誤輸出(fd分別為0、1、2)用參數傳來的descriptors代替,實際上傳來的就是“/dev/null”,可以隨便進入一個app的fd可以看到0、1、2一定是/dev/null。接下來,Ams傳來的參數中有“--runtime-init”並且invokeWith的是ActivityThead,然后執行RuntimeInit.zygoteInit這個方法。

step4 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();
        /*設置時區、log、http代理等一些信息*/
        commonInit();
        nativeZygoteInit();
        applicationInit(targetSdkVersion, argv, classLoader);
    }

commonInit是一些通用的初始化,不用去深究,下面重點看一下nativeZygoteInit(比較重要的方法一般都是放在native去干的)和applicationInit。

nativeZygoteInit

通過一系列繼承、重寫的技巧,總之最后調用到了app_main.cpp中
.frameworks/base/cmds/app_process/app_main.cpp

virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }

如果你熟悉native binder進程的寫法的話,對這兩句話一定不陌生,又看到了熟悉的套路。這兩句話在app啟動之前幫忙打開了/dev/binder,同時啟動了binder線程池。之后app在使用binder時就不用關心binder驅動以及線程池相關的事兒了。

applicationInit

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) {
        throw new RuntimeException(
                "Missing class when invoking static main " + className,
                ex);
    }

    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        throw new RuntimeException(
                "Missing static main on " + className, ex);
    } catch (SecurityException ex) {
        throw new RuntimeException(
                "Problem getting static main on " + className, ex);
    }

    int modifiers = m.getModifiers();
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        throw new RuntimeException(
                "Main method is not public and static on " + className);
    }

    /*
     * 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.
     */
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

程序比較簡單,主要是通過反射的方式找到ActivityThread的main方法,並且拋出異常把該方法作為參數傳遞到zygote的main方法中去(前面講了zygote的main方法除了開啟selectLoop還捕獲了MethodAndArgsCaller這個異常)。

    /**
     * Helper exception class which holds a method and arguments and
     * can call them. This is used as part of a trampoline to get rid of
     * the initial process setup stack frames.
     */
    public static class MethodAndArgsCaller extends Exception
            implements Runnable {
        /** method to call */
        private final Method mMethod;

        /** argument array */
        private final String[] mArgs;

        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }

        public void run() {
            try {
                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);
            }
        }
    }

MethodAndArgsCaller的run方法很簡單,其實就是去執行ActivityThread的main方法。現在我們來捋一下,zygote饒了這么大一圈,就是為了fork出子進程,做一些binder線程池等的准備工作,最后執行ActivityThread的main方法。
通過調用棧來總結一下子進程創建生命的過程

1896-1896/com.android.myapplication W:     at com.android.internal.os.RuntimeInit.invokeStaticMain(RuntimeInit.java:237)
1896-1896/com.android.myapplication W:     at com.android.internal.os.RuntimeInit.applicationInit(RuntimeInit.java:338)
1896-1896/com.android.myapplication W:     at com.android.internal.os.RuntimeInit.zygoteInit(RuntimeInit.java:290)
1896-1896/com.android.myapplication W:     at com.android.internal.os.ZygoteConnection.handleChildProc(ZygoteConnection.java:757)
1896-1896/com.android.myapplication W:     at com.android.internal.os.ZygoteConnection.runOnce(ZygoteConnection.java:243)
1896-1896/com.android.myapplication W:     at com.android.internal.os.ZygoteInit.runSelectLoop(ZygoteInit.java:876)
1896-1896/com.android.myapplication W:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:798)

注意雖然看pid這是子進程的pid號,但是繼承了父進程的調用棧,從handleChildProc開始是子進程,之前是父進程zygote。

step5 ActivityThread -- app的入口

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

這次我們主要看一下ActivityThread的靜態main方法,因為整個文件有6000多行,關系到Activity實例的各種生命周期和管理、以及viewroot的創建等等。

    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

主要是調用Looper的靜態方法創建消息循環,然后創建ActivityThread實例,最后進入到消息循環中。

總結

通過本文大致理了從Ams開始創建一個app進程的大致流程,如果以執行的進程實體來看,其實主要分三個部分,一個是ams中,一個是zygote父進程中,一個是子進程中。有了這個大致的脈絡,再根據調用棧來看,實際還是比較清晰的。ams負責接收binder請求並與zygote聯系,zygote父進程收到socket消息后去fork出子進程,子進程負責准備好binder環境和消息循環,然后開始Activity的生命周期。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM