Android應用程序進程啓動過程(前篇)

在此前我講過Android系統的啓動流程,系統啓動後,咱們就比較關心應用程序是如何啓動的,這一篇咱們來一塊兒學習Android7.0 應用程序進程啓動過程,須要注意的是「應用程序進程啓動過程」,而不是應用程序啓動過程。關於應用程序啓動過程,我會在後續系列的文章中講到。java

1.應用程序進程概述

  要想啓動一個應用程序,首先要保證這個應用程序所須要的應用程序進程已經被啓動。ActivityManagerService在啓動應用程序時會檢查這個應用程序須要的應用程序進程是否存在,不存在就會請求Zygote進程將須要的應用程序進程啓動。在Android系統啓動流程(二)解析Zygote進程啓動過程這篇文章中,我提到了Zygote的Java框架層中,會建立一個Server端的Socket,這個Socket用來等待ActivityManagerService來請求Zygote來建立新的應用程序進程的。咱們知道Zygote進程經過fock自身建立的應用程序進程,這樣應用程序程序進程就會得到Zygote進程在啓動時建立的虛擬機實例。固然,在應用程序建立過程當中除了獲取虛擬機實例,還能夠得到Binder線程池和消息循環,這樣運行在應用進程中應用程序就能夠方便的使用Binder進行進程間通訊以及消息處理機制了。關於Binder線程池和消息循環是如何啓動或者建立的會在下一篇文章給出答案。先給出應用程序進程啓動過程的時序圖,而後對每個步驟進行詳細分析,以下圖所示。android

2.應用程序進程建立過程

發送建立應用程序進程請求

ActivityManagerService會經過調用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) {
        ...
        try {
            try {
                final int userId = UserHandle.getUserId(app.uid);
                AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }

            int uid = app.uid;//1
            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            if (!app.isolated) {
              ...
              /**
              * 2 對gids進行建立和賦值
              */
                if (ArrayUtils.isEmpty(permGids)) {
                    gids = new int[2];
                } else {
                    gids = new int[permGids.length + 2];
                    System.arraycopy(permGids, 0, gids, 2, permGids.length);
                }
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
            }

           ...
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";//3
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkTime(startTime, "startProcess: asking zygote to start proc");
            /**
            * 4
            */
            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);
           ...
        } catch (RuntimeException e) {
          ...
        }
    }
   ...
    }


在註釋1處的達到建立應用程序進程的用戶ID,在註釋2處對用戶組ID:gids進行建立和賦值。註釋3處若是entryPoint 爲null則賦值爲」android.app.ActivityThread」。在註釋4處調用Process的start函數,將此前獲得的應用程序進程用戶ID和用戶組ID傳進去,第一個參數entryPoint咱們得知是」android.app.ActivityThread」,後文會再次提到它。接下來咱們來查看Process的start函數,以下所示。 
frameworks/base/core/java/android/os/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 {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                debugFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {
      ...
    }
}


start函數中只調用了startViaZygote函數: 
frameworks/base/core/java/android/os/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) {
        /**
        * 1
        */
            ArrayList<String> argsForZygote = new ArrayList<String>();
            argsForZygote.add("--runtime-args");
            argsForZygote.add("--setuid=" + uid);
            argsForZygote.add("--setgid=" + gid);
          ...
            if (gids != null && gids.length > 0) {
                StringBuilder sb = new StringBuilder();
                sb.append("--setgroups=");

                int sz = gids.length;
                for (int i = 0; i < sz; i++) {
                    if (i != 0) {
                        sb.append(',');
                    }
                    sb.append(gids[i]);
                }

                argsForZygote.add(sb.toString());
            }
         ...
            argsForZygote.add(processClass);
            if (extraArgs != null) {
                for (String arg : extraArgs) {
                    argsForZygote.add(arg);
                }
            }
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

在註釋1處建立了字符串列表argsForZygote ,並將啓動應用進程的啓動參數保存在argsForZygote中,函數的最後會調用zygoteSendArgsAndGetResult函數,須要注意的是,zygoteSendArgsAndGetResult函數中第一個參數中調用了openZygoteSocketIfNeeded函數,而第二個參數是保存應用進程的啓動參數的argsForZygote。zygoteSendArgsAndGetResult函數以下所示。 
frameworks/base/core/java/android/os/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();
            // Should there be a timeout on this?
            ProcessStartResult result = new ProcessStartResult();
            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);
        }
    }

zygoteSendArgsAndGetResult函數主要作的就是將傳入的應用進程的啓動參數argsForZygote,寫入到ZygoteState中,結合上文咱們知道ZygoteState實際上是由openZygoteSocketIfNeeded函數返回的,那麼咱們接着來看openZygoteSocketIfNeeded函數,代碼以下所示。 
frameworks/base/core/java/android/os/Process.java
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        try {
            primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);//1
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
        }
    }
    if (primaryZygoteState.matches(abi)) {//2
        return primaryZygoteState;
    }
    // The primary zygote didn't match. Try the secondary.
    if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
        try {
        secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);//3
        } 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);

在講到Zygote進程啓動過程時咱們得知,在Zygote的main函數中會建立name爲「zygote」的Server端Socket。在註釋1處會調用ZygoteState的connect函數與名稱爲ZYGOTE_SOCKET的Socket創建鏈接,這裏ZYGOTE_SOCKET的值爲「zygote」。註釋2處若是鏈接name爲「zygote」的Socket返回的primaryZygoteState與當前的abi不匹配,則會在註釋3處鏈接name爲「zygote_secondary」的Socket。這兩個Socket區別就是:name爲」zygote」的Socket是運行在64位Zygote進程中的,而name爲「zygote_secondary」的Socket則運行在32位Zygote進程中。既然應用程序進程是經過Zygote進程fock產生的,當要鏈接Zygote中的Socket時,也須要保證位數的一致。
View Code

接收請求並建立應用程序進程

Socket進行鏈接成功並匹配abi後會返回ZygoteState類型對象,咱們在分析zygoteSendArgsAndGetResult函數中講過,會將應用進程的啓動參數argsForZygote寫入到ZygoteState中,這樣Zygote進程就會收到一個建立新的應用程序進程的請求,咱們回到ZygoteInit的main函數,以下所示。

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
       ...
        try {
         ...       
            //註冊Zygote用的Socket
            registerZygoteSocket(socketName);//1
           ...
           //預加載類和資源
           preload();//2
           ...
            if (startSystemServer) {
            //啓動SystemServer進程
                startSystemServer(abiList, socketName);//3
            }
            Log.i(TAG, "Accepting command socket connections");
            //等待客戶端請求
            runSelectLoop(abiList);//4
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

這些內容在Android系統啓動流程(二)解析Zygote進程啓動過程講過,但爲了更好的理解我再講一遍。註釋1處經過registerZygoteSocket函數來建立一個Server端的Socket,這個name爲」zygote」的Socket用來等待ActivityManagerService來請求Zygote來建立新的應用程序進程。註釋2處用來預加載類和資源。註釋3處用來啓動SystemServer進程,這樣系統的關鍵服務也會由SystemServer進程啓動起來。註釋4處調用runSelectLoop函數來等待ActivityManagerService的請求。咱們就來查看runSelectLoop函數:

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();//2
        fds.add(sServerSocket.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 {
                    boolean done = peers.get(i).runOnce();//1
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

當有ActivityManagerService的請求數據到來時會調用註釋1處的代碼,結合註釋2處的代碼,咱們得知註釋1處的代碼實際上是調用ZygoteConnection的runOnce函數來處理請求的數據: 
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
 boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
        try {
            args = readArgumentList();//1
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }
...
        try {
            parsedArgs = new Arguments(args);//2
        ...
        /**
        * 3 
        */
            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) {
          ....
        }
       try {
            if (pid == 0) {
                // in child
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                return true;
            } else {
                // in parent...pid of < 0 means failure
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }

在註釋1處調用readArgumentList函數來獲取應用程序進程的啓動參數,並在註釋2處將readArgumentList函數返回的字符串封裝到Arguments對象parsedArgs中。註釋3處調用Zygote的forkAndSpecialize函數來建立應用程序進程,參數爲parsedArgs中存儲的應用進程啓動參數,返回值爲pid。forkAndSpecialize函數主要是經過fork當前進程來建立一個子進程的,若是pid等於0,則說明是在新建立的子進程中執行的,就會調用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 {
      ...
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }

handleChildProc函數中調用了RuntimeInit的zygoteInit函數,以下所示。 
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
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();
        nativeZygoteInit();//1
        applicationInit(targetSdkVersion, argv, classLoader);//2
    }

註釋1處會在新建立的應用程序進程中建立Binder線程池,這個在下一篇文章會詳細介紹。在註釋2處調用了applicationInit函數: 
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
 ...
        final Arguments args;
        try {
            args = new Arguments(argv);
        } catch (IllegalArgumentException ex) {
            Slog.e(TAG, ex.getMessage());       
            return;
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        invokeStaticMain(args.startClass, args.startArgs, classLoader);//1
    }

在applicationInit中會在註釋1處調用invokeStaticMain函數,須要注意的是第一個參數args.startClass,這裏指的就是此篇文章開頭提到的參數:android.app.ActivityThread。接下來咱們查看invokeStaticMain函數,以下所示。 
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;
    try {
        cl = Class.forName(className, true, classLoader);//1
    } 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 });//2
    } catch (NoSuchMethodException ex) {
        throw new RuntimeException(
                "Missing static main on " + className, ex);
    }
    ...
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);//3
}

能夠看到註釋1處經過反射來得到android.app.ActivityThread類,接下來在註釋2處來得到ActivityThread的main函數,並將main函數傳入到註釋3處的ZygoteInit中的MethodAndArgsCaller類的構造函數中,MethodAndArgsCaller類內部會經過反射調用ActivityThread的main函數,這樣應用程序進程就建立完成了。
View Code
相關文章
相關標籤/搜索