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


在此前我講過Android系統的啟動流程,系統啟動后,我們就比較關心應用程序是如何啟動的,這一篇我們來一起學習Android7.0 應用程序進程啟動過程,需要注意的是“應用程序進程啟動過程”,而不是應用程序啟動過程。關於應用程序啟動過程,我會在后續系列的文章中講到。

1.應用程序進程概述

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

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

 

 

 


免責聲明!

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



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