Android進程系列第五篇---應(yīng)用進程的創(chuàng)建流程

一恋博、內(nèi)容預(yù)覽

應(yīng)用進程的創(chuàng)建.png

二、概述

前面進程系列已經(jīng)更新了四篇葵蒂,本文(基于Android O源碼)交播,梳理應(yīng)用進程的創(chuàng)建流程重虑。
進程系列第一篇---進程基礎(chǔ)
進程系列第二篇---Zygote進程的創(chuàng)建流程
Android進程第三篇---SystemServer進程創(chuàng)建流程
Android進程第四篇---SystemServer進程的啟動流程

下面是一個進程創(chuàng)建架構(gòu)圖践付,可以了解一個進程創(chuàng)建的大概流程。


應(yīng)用進程創(chuàng)建架構(gòu)圖.png

一共涉及了幾個角色缺厉,發(fā)起進程永高、System進程、Zygote進程提针、新進程

  • 發(fā)起進程
    一個App進程可以通過startActivity等系統(tǒng)API請求SystemServer進程創(chuàng)建進程命爬,SystemServer進程把這個活交給了Process.start,這個就是創(chuàng)建進程的入口辐脖。

  • System進程
    緊接著SystemServer進程通知ZygoteState創(chuàng)建LocalSocket饲宛,此時,SystemServer進程一直扮演的都是客戶端的角色嗜价。

  • Zygote進程
    另一方面艇抠,在Android開機的過程中幕庐,Zygote進程就已經(jīng)早早的啟動了,所以LocalServerSocket就已經(jīng)很早創(chuàng)建了家淤,runSelectLoop開啟了一個死循環(huán)一直accept客戶端的連接异剥,當SystemServer進程把LocalSocket創(chuàng)建出來之后,就可以使用LocalSocket send/recv數(shù)據(jù)了絮重,此時就可以通知LocalServerSocket我要創(chuàng)建一個進程冤寿。進程fork完成之后,返回結(jié)果給System進程的AMS青伤。

  • 新進程
    Zygote進程把進程fork出來之后督怜,需要做進程的初始化操作,比如設(shè)置進程異常的捕獲方式狠角,開始Binder線程池等等亮蛔,最后進入了ActivityThread的main方法,一個有血有肉的進程正式被啟動了擎厢。

三究流、進程的創(chuàng)建流程

3.1、發(fā)送創(chuàng)建請求动遭,從Process類的start方法開始

所有進程創(chuàng)建的請求都交給Process芬探,從Process類的start方法開始。

frameworks/base/core/java/android/os/Process.java
/**
    * Start a new process.
    * 
    * <p>If processes are enabled, a new process is created and the
    * static main() function of a <var>processClass</var> is executed there.
    * The process will continue running after this function returns.
    * 
    * <p>If processes are not enabled, a new thread in the caller's
    * process is created and main() of <var>processClass</var> called there.
    * 
    * <p>The niceName parameter, if not an empty string, is a custom name to
    * give to the process instead of using processClass.  This allows you to
    * make easily identifyable processes even if you are using the same base
    * <var>processClass</var> to start them.
    * 
    * When invokeWith is not null, the process will be started as a fresh app
    * and not a zygote fork. Note that this is only allowed for uid 0 or when
    * debugFlags contains DEBUG_ENABLE_DEBUGGER.
    *
    * @param processClass The class to use as the process's main entry
    *                     point.
    * @param niceName A more readable name to use for the process.
    * @param uid The user-id under which the process will run.
    * @param gid The group-id under which the process will run.
    * @param gids Additional group-ids associated with the process.
    * @param debugFlags Additional flags.
    * @param targetSdkVersion The target SDK version for the app.
    * @param seInfo null-ok SELinux information for the new process.
    * @param abi non-null the ABI this app should be started with.
    * @param instructionSet null-ok the instruction set to use.
    * @param appDataDir null-ok the data directory of the app.
    * @param invokeWith null-ok the command to invoke with.
    * @param zygoteArgs Additional arguments to supply to the zygote process.
    * 
    * @return An object that describes the result of the attempt to start the process.
    * @throws RuntimeException on fatal start failure
    * 
    * {@hide}
    */
   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 invokeWith,
                                 String[] zygoteArgs) {
       return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                   debugFlags, mountExternal, targetSdkVersion, seInfo,
                   abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
   }

舉例:當啟動一個Activity的時候厘惦,發(fā)現(xiàn)Activity所在進程沒有被創(chuàng)建偷仿,就會調(diào)用這個API進程進行創(chuàng)建闲孤。Process.start()方法是阻塞操作谆沃,等待直到進程創(chuàng)建完成并返回相應(yīng)的新進程pid培漏,才完成該方法脑慧。

  ProcessStartResult  startResult = Process.start(entryPoint,
                       app.processName, uid, uid, gids, debugFlags, mountExternal,
                       app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                       app.info.dataDir, invokeWith, entryPointArgs);
           }

為了更好的理解各個參數(shù)的含義吕朵,我debug一下炊琉,得到的各個參數(shù)值如下圖(我調(diào)試的過程中發(fā)現(xiàn)九火,頭條一啟動就有很多進程跟著起來钻弄,做ROM工程師真是累啊稼稿,雖然只是打開一個應(yīng)用薄榛,背后喚醒的都不止10個進程,每個進程都需要申請系統(tǒng)的資源让歼,相信每一家ROM對進程的存活都有嚴格的把控3怠)


頭條啟動.png
3.2、整理進程創(chuàng)建的請求參數(shù)

在Process.start之后谋右,有幾個鏈條式的調(diào)用硬猫,Process.start->ZygoteProcess.start->ZygoteProcess.startViaZygote,返回ZygoteState,ZygoteState封裝了Socket的輸入和輸出流啸蜜,zygoteInputStream與zygoteWrite馏予,zygoteWrite可以把創(chuàng)建進程的參數(shù)從SystemServer進程傳遞到Zygote進程,zygoteInputStream可以把返回結(jié)果從Zygote進程返回到SystemServer進程盔性。以下幾個調(diào)用就是不斷的封裝并傳遞創(chuàng)建進程的請求參數(shù)霞丧。

/frameworks/base/core/java/android/os/ZygoteProcess.java
195    public final Process.ProcessStartResult start(final String processClass,
196                                                  final String niceName,
197                                                  int uid, int gid, int[] gids,
198                                                  int debugFlags, int mountExternal,
199                                                  int targetSdkVersion,
200                                                  String seInfo,
201                                                  String abi,
202                                                  String instructionSet,
203                                                  String appDataDir,
204                                                  String invokeWith,
205                                                  String[] zygoteArgs) {
206        try {
207            return startViaZygote(processClass, niceName, uid, gid, gids,
208                    debugFlags, mountExternal, targetSdkVersion, seInfo,
209                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
210        } catch (ZygoteStartFailedEx ex) {
211            Log.e(LOG_TAG,
212                    "Starting VM process through Zygote failed");
213            throw new RuntimeException(
214                    "Starting VM process through Zygote failed", ex);
215        }
216    }
 /frameworks/base/core/java/android/os/ZygoteProcess.java
329    private Process.ProcessStartResult startViaZygote(final String processClass,
330                                                      final String niceName,
331                                                      final int uid, final int gid,
332                                                      final int[] gids,
333                                                      int debugFlags, int mountExternal,
334                                                      int targetSdkVersion,
335                                                      String seInfo,
336                                                      String abi,
337                                                      String instructionSet,
338                                                      String appDataDir,
339                                                      String invokeWith,
340                                                      String[] extraArgs)
341                                                      throws ZygoteStartFailedEx {
342        ArrayList<String> argsForZygote = new ArrayList<String>();
            ......
430        synchronized(mLock) {
431            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
432        }
433    }

該過程主要工作是生成argsForZygote列表,把startViaZygote方法的參數(shù)存放到這個列表里面冕香。并且調(diào)用zygoteSendArgsAndGetResult請求Zygotefork進程蛹尝。

3.3、創(chuàng)建Socket悉尾,給Zygote進程發(fā)送進程創(chuàng)建的請求參數(shù)
 /frameworks/base/core/java/android/os/ZygoteProcess.java
454    @GuardedBy("mLock")
455    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
456        Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
457
458        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
459            try {
460                primaryZygoteState = ZygoteState.connect(mSocket);
461            } catch (IOException ioe) {
462                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
463            }
464        }
465
466        if (primaryZygoteState.matches(abi)) {
467            return primaryZygoteState;
468        }
469
470        // The primary zygote didn't match. Try the secondary.
471        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
472            try {
473                secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
474            } catch (IOException ioe) {
475                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
476            }
477        }
478        //判斷當前的abi來選擇與zygote還是zygote64來進行通信
479        if (secondaryZygoteState.matches(abi)) {
480            return secondaryZygoteState;
481        }
482
483        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
484    }

通過前面的文章可知道突那,Zygote進程有兩個Socket,這里當主zygote沒能匹配成功构眯,則嘗試第二個mSecondarySocket來連接愕难。

 /frameworks/base/core/java/android/os/ZygoteProcess.java
92        public static ZygoteState connect(String socketAddress) throws IOException {
93            DataInputStream zygoteInputStream = null;
94            BufferedWriter zygoteWriter = null;
95            final LocalSocket zygoteSocket = new LocalSocket();
96
97            try {
98                zygoteSocket.connect(new LocalSocketAddress(socketAddress,
99                        LocalSocketAddress.Namespace.RESERVED));
100
101                zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
102
103                zygoteWriter = new BufferedWriter(new OutputStreamWriter(
104                        zygoteSocket.getOutputStream()), 256);
105            } catch (IOException ex) {
106                try {
107                    zygoteSocket.close();
108                } catch (IOException ignore) {
109                }
110
111                throw ex;
112            }
113
114            String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
115            Log.i("Zygote", "Process: zygote socket " + socketAddress + " opened, supported ABIS: "
116                    + abiListString);
117
118            return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
119                    Arrays.asList(abiListString.split(",")));
120        }

這個方法主要是建立了SystemServer(Client)這一邊的Socket---LocalSocket,與Zygote進程的LocalServerSocket成功連接之后惫霸,獲取這個LocalSocket的輸入流zygoteInputStream與輸出流zygoteWriter猫缭,并且將他們封裝到ZygoteState中再返回。關(guān)于Socket的工作原理壹店,移步本系列第三篇博客猜丹。

253    @GuardedBy("mLock")
254    private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
255            ZygoteState zygoteState, ArrayList<String> args)
256            throws ZygoteStartFailedEx {
257        try {
258            // Throw early if any of the arguments are malformed. This means we can
259            // avoid writing a partial response to the zygote.
260            int sz = args.size();
261            for (int i = 0; i < sz; i++) {
262                if (args.get(i).indexOf('\n') >= 0) {
263                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
264                }
265            }
266
               ........
                  //1、從ZygoteState中取出輸入流和輸出流
277            final BufferedWriter writer = zygoteState.writer;
278            final DataInputStream inputStream = zygoteState.inputStream;
279            //2硅卢、用輸入流將創(chuàng)建進程的參數(shù)傳遞給Zygote進程
280            writer.write(Integer.toString(args.size()));
281            writer.newLine();
282
283            for (int i = 0; i < sz; i++) {
284                String arg = args.get(i);
285                writer.write(arg);
286                writer.newLine();
287            }
288
289            writer.flush();
290
291            //創(chuàng)建Process.ProcessStartResult用于存放fork進程的返回結(jié)果
292            Process.ProcessStartResult result = new Process.ProcessStartResult();
293
294            // Always read the entire result from the input stream to avoid leaving
295            // bytes in the stream for future process starts to accidentally stumble
296            // upon.
                  //輸入流讀取Zygote進程創(chuàng)建進程之后返回的數(shù)據(jù)射窒,保存在Process.ProcessStartResult中
297            result.pid = inputStream.readInt();
298            result.usingWrapper = inputStream.readBoolean();
299            //通過判斷result.pid 是否創(chuàng)建成功
300            if (result.pid < 0) {
301                throw new ZygoteStartFailedEx("fork() failed");
302            }
303            return result;
304        } catch (IOException ex) {
305            zygoteState.close();
306            throw new ZygoteStartFailedEx(ex);
307        }
308    }

這段做的工作主要是從ZygoteState中取出輸入流和輸出流,然后和Server端的Zygote進程的LocketServerSocket進行通信将塑。將AMS中創(chuàng)建進程的參數(shù)傳遞給Zygote進程脉顿。Zygote進程fork完成之后, inputStream.readInt()就能讀取出返回結(jié)果点寥,如果小于0艾疟,代表創(chuàng)建失敗,不小于0代表創(chuàng)建成功开财。
這段代碼存在一個問題汉柒,如果Zygote進程fork進程超時,System這段遲遲不能get到返回結(jié)果责鳍,會引起什么后果?

試想一下兽间,當 AMS 需要創(chuàng)建進程時, 會通過 Socket 與 zygote 進程通信, 當 zygote 接收到請求后會 fork 出一個子進程, 并將其 pid 返回給 AMS历葛。需要注意的是, 在收到 pid 之前, AMS 會一直持鎖等待,而且這里持有的是AMS大鎖, 所以就會 block 其他重要線程, 導(dǎo)致系統(tǒng)卡死,用戶反饋內(nèi)容也會主要圍繞 "系統(tǒng)卡死" "按鍵沒有反應(yīng)" 等等恤溶。

那如何解決這個問題乓诽?google其實有注意到,準備加一個超時機制咒程,但是一直沒有加上鸠天,但是這種情況也是治標不治本,解決這種問題還是要具體分析帐姻,是內(nèi)存碎片嚴重導(dǎo)致fork進程申請page失敗稠集,還是其他原因,需要根據(jù)Log具體對待饥瓷。

3.4剥纷、Zygote進程接收請求參數(shù)

到這里,Client段的工作就全部看完了呢铆,現(xiàn)在去看看Socket的服務(wù)端晦鞋。再次回顧一下那段“模板”代碼。

  frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
 public static void main(String argv[]) {
        //1棺克、創(chuàng)建ZygoteServer
        ZygoteServer zygoteServer = new ZygoteServer();
        try {
            //2悠垛、創(chuàng)建一個Server端的Socket
            zygoteServer.registerServerSocket(socketName);
            //3、加載進程的資源和類
            preload(bootTimingsTraceLog);
            if (startSystemServer) {
                //4娜谊、開啟SystemServer進程鼎文,這是受精卵進程的第一次分裂
                startSystemServer(abiList, socketName, zygoteServer);
            }
            //5、啟動一個死循環(huán)監(jiān)聽來自Client端的消息
            zygoteServer.runSelectLoop(abiList);
             //6因俐、關(guān)閉SystemServer的Socket
            zygoteServer.closeServerSocket();
        } catch (Zygote.MethodAndArgsCaller caller) {
             //7拇惋、這里捕獲這個異常調(diào)用MethodAndArgsCaller的run方法。
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }

注釋寫的很詳細了抹剩,不多做解釋撑帖,直接看runSelectLoop方法。

 /frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
136    void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
137        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
138        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
139        //將服務(wù)端LocalServerSocket的fd加進fds中
140        fds.add(mServerSocket.getFileDescriptor());
141        peers.add(null);
142
143        while (true) {
144            StructPollfd[] pollFds = new StructPollfd[fds.size()];
145            for (int i = 0; i < pollFds.length; ++i) {
146                pollFds[i] = new StructPollfd();
147                pollFds[i].fd = fds.get(i);
148                pollFds[i].events = (short) POLLIN;
149            }
150            try {
                    //處理輪詢狀態(tài)澳眷,當pollFds有事件到來則往下執(zhí)行胡嘿,否則阻塞在這里
151                Os.poll(pollFds, -1);
152            } catch (ErrnoException ex) {
153                throw new RuntimeException("poll failed", ex);
154            }
                //當接收到客戶端發(fā)出連接請求 或者數(shù)據(jù)處理請求到來,則往下執(zhí)行钳踊;否則進入continue衷敌,跳出本次循環(huán)。
155            for (int i = pollFds.length - 1; i >= 0; --i) {
156                if ((pollFds[i].revents & POLLIN) == 0) {
157                    continue;
158                }
                     //當i為0的時候拓瞪,創(chuàng)建ZygoteConnection缴罗,實質(zhì)就創(chuàng)建LocalServerSocket
159                if (i == 0) {
160                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
161                    peers.add(newPeer);
                          //將LocalServerSocket的fd添加到fds
162                    fds.add(newPeer.getFileDesciptor());
163                } else {
                          將LocalServerSocket的fd取出來,執(zhí)行runOnce
164                    boolean done = peers.get(i).runOnce(this);
165                    if (done) {
                              //完成之后將fd與ZygoteConnection移除
166                        peers.remove(i);
167                        fds.remove(i);
168                    }
169                }
170            }
171        }
172    }
173}

runSelectLoop中有一個while死循環(huán)祭埂,接收進程創(chuàng)建請求面氓,當來了一個請求,就會走runOnce方法

78    /**
79     * Waits for and accepts a single command connection. Throws
80     * RuntimeException on failure.
81     */
82    private ZygoteConnection acceptCommandPeer(String abiList) {
83        try {
84            return createNewConnection(mServerSocket.accept(), abiList);
85        } catch (IOException ex) {
86            throw new RuntimeException(
87                    "IOException during accept()", ex);
88        }
89    }

acceptCommandPeer中調(diào)用createNewConnection,返回值是一個ZygoteConnection舌界,封裝了mServerSocket的輸入流mSocketReader與輸出流mSocketOutStream掘譬,這個與Clinet端的ZygoteState有著異曲同工之妙啊。

/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
91    ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
92        mSocket = socket;
93        this.abiList = abiList;
94        
95        mSocketOutStream
96                = new DataOutputStream(socket.getOutputStream());
97
98        mSocketReader = new BufferedReader(
99                new InputStreamReader(socket.getInputStream()), 256);
100
101        mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
102
103        try {
104            peer = mSocket.getPeerCredentials();
105        } catch (IOException ex) {
106            Log.e(TAG, "Cannot read peer credentials", ex);
107            throw ex;
108        }
109    }
3.5呻拌、Zygote進程處理創(chuàng)建進程請求葱轩,fork進程

在ZygoteConnection創(chuàng)建好了之后,就執(zhí)行runOnce真正處理進程的創(chuàng)建請求了藐握。

/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
134    boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
135
136        String args[];
137        Arguments parsedArgs = null;
138        FileDescriptor[] descriptors;
139
140        try {
                 //把進程創(chuàng)建的參數(shù)讀取出來
141            args = readArgumentList();
142            descriptors = mSocket.getAncillaryFileDescriptors();
143        } catch (IOException ex) {
144            Log.w(TAG, "IOException on command socket " + ex.getMessage());
145            closeSocket();
146            return true;
147        }
148
149        if (args == null) {
150            // EOF reached.
                  //參數(shù)為null靴拱,需要關(guān)閉之前創(chuàng)建的Socket,進程創(chuàng)建請求參數(shù)為null還沒有仔細的調(diào)查過
151            closeSocket();
152            return true;
153        }
              ........
162
163        int pid = -1;
164        FileDescriptor childPipeFd = null;
165        FileDescriptor serverPipeFd = null;
166
167        try {
                  //將進程創(chuàng)建請求參數(shù)整理成Arguments對象 
168            parsedArgs = new Arguments(args);
               ........
238            //創(chuàng)建子進程,底層調(diào)用fork函數(shù)趾娃,返回值有兩個缭嫡,基于寫時復(fù)制
239            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
240                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
241                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
242                    parsedArgs.appDataDir);
243        } catch (ErrnoException ex) {
244            logAndPrintError(newStderr, "Exception creating pipe", ex);
245        } catch (IllegalArgumentException ex) {
246            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
247        } catch (ZygoteSecurityException ex) {
248            logAndPrintError(newStderr,
249                    "Zygote security policy prevents request: ", ex);
250        }
251
252        try {
                 //pid==0代表是新創(chuàng)建的子進程
253            if (pid == 0) {
254                //關(guān)閉從Zygote進程繼承而來的Socket
255                zygoteServer.closeServerSocket();
256                IoUtils.closeQuietly(serverPipeFd);
257                serverPipeFd = null;
                      //處理子進程接下來的工作
258                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
259
260                // should never get here, the child is expected to either
261                // throw Zygote.MethodAndArgsCaller or exec().
262                return true;
263            } else {
264               //大于0,是父進程抬闷,也就是Zygote進程
265                IoUtils.closeQuietly(childPipeFd);
266                childPipeFd = null;
                     //處理父進程接下來的工作
267                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
268            }
269        } finally {
270            IoUtils.closeQuietly(childPipeFd);
271            IoUtils.closeQuietly(serverPipeFd);
272        }
273    }

在調(diào)用Zygote.forkAndSpecialize之前妇蛀,需要調(diào)用readArgumentList把創(chuàng)建進程的請求參數(shù)從Socket中讀取出來,放在一個名為result的String數(shù)組中笤成。

/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
631    /**
632     * Reads an argument list from the command socket/
633     * @return Argument list or null if EOF is reached
634     * @throws IOException passed straight through
635     */
636    private String[] readArgumentList()
637            throws IOException {
            ......
649        int argc;
650
651        try {
652            String s = mSocketReader.readLine();
653
654            if (s == null) {
655                // EOF reached.
656                return null;
657            }
658            argc = Integer.parseInt(s);
659        } catch (NumberFormatException ex) {
660            Log.e(TAG, "invalid Zygote wire format: non-int at argc");
661            throw new IOException("invalid wire format");
662        }
663
664        // See bug 1092107: large argc can be used for a DOS attack
665        if (argc > MAX_ZYGOTE_ARGC) {
666            throw new IOException("max arg count exceeded");
667        }
668
669        String[] result = new String[argc];
670        for (int i = 0; i < argc; i++) {
671            result[i] = mSocketReader.readLine();
672            if (result[i] == null) {
673                // We got an unexpected EOF.
674                throw new IOException("truncated request");
675            }
676        }
677
678        return result;
679    }

參數(shù)有了就調(diào)用Zygote.forkAndSpecialize方法fork進程了评架,關(guān)于進程的fork,第三篇寫的更詳細炕泳,這里不贅述纵诞。

99    public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
100          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
101          int[] fdsToIgnore, String instructionSet, String appDataDir) {
102        VM_HOOKS.preFork();
103        // Resets nice priority for zygote process.
104        resetNicePriority();
             //jni技術(shù)調(diào)用fork函數(shù)
105        int pid = nativeForkAndSpecialize(
106                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
107                  fdsToIgnore, instructionSet, appDataDir);
108        // Enable tracing as soon as possible for the child process.
109        if (pid == 0) {
110            Trace.setTracingEnabled(true);
111
112            // Note that this event ends at the end of handleChildProc,
113            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
114        }
115        VM_HOOKS.postForkCommon();
116        return pid;
117    }
3.6、進程創(chuàng)建成功培遵,新進程做初始化

當forkAndSpecialize完成之后浙芙,進程就被創(chuàng)建出來了,但是這個進程是光禿禿的籽腕,還需一些工作要處理嗡呼,即走進handleChildProc方法。

786    private void handleChildProc(Arguments parsedArgs,
787            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
788            throws Zygote.MethodAndArgsCaller {
               .......
               //設(shè)置進程名字
811        if (parsedArgs.niceName != null) {
812            Process.setArgV0(parsedArgs.niceName);
813        }
814
815        // End of the postFork event.
816        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
817        if (parsedArgs.invokeWith != null) {
818            WrapperInit.execApplication(parsedArgs.invokeWith,
819                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
820                    VMRuntime.getCurrentInstructionSet(),
821                    pipeFd, parsedArgs.remainingArgs);
822        } else {
                   //做進程的一些初始化操作皇耗,與System進程創(chuàng)建一致的
823            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
824                    parsedArgs.remainingArgs, null /* classLoader */);
825        }
826    }
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
829    public static final void zygoteInit(int targetSdkVersion, String[] argv,
830            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
831        if (RuntimeInit.DEBUG) {
832            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
833        }
834
835        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
          //見本系列第三篇文章3.5.1
836        RuntimeInit.redirectLogStreams();
837       //見本系列第三篇文章3.5.2
838        RuntimeInit.commonInit();
           //見本系列第三篇文章3.5.3
839        ZygoteInit.nativeZygoteInit();
          //見本系列第三篇文章3.5.4
840        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
841    }
842

zygoteInit與System進程創(chuàng)建是一致的南窗,每個進程在創(chuàng)建出來之后,都需要做四件事情郎楼。

  • 重定向log輸出
  • 通用的一些初始化万伤,比如設(shè)置進程的異常捕獲方式、時區(qū)等
  • 調(diào)用nativeZygoteInit進行Zygote的初始化呜袁,開啟Binder線程池
  • 調(diào)用applicationInit進行應(yīng)用的初始化
    在此不贅述敌买,可移步見本系列第三篇文章。這里看一下applicationInit進行應(yīng)用的初始化傅寡。
 /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
289    protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
290            throws Zygote.MethodAndArgsCaller {
              .....
303        final Arguments args;
304        try {
305            args = new Arguments(argv);
306        } catch (IllegalArgumentException ex) {
307            Slog.e(TAG, ex.getMessage());
308            // let the process exit
309            return;
310        }
              .....
315        // 喚醒進程的main方法
316        invokeStaticMain(args.startClass, args.startArgs, classLoader);
317    }

此處的args.startClass為android.app.ActivityThread.java放妈,當fork System進程的時候北救,args.startClass為com.android.server.SystemServer.java荐操。

/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
231    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
232            throws Zygote.MethodAndArgsCaller {
233        Class<?> cl;
234
235        try {
236            cl = Class.forName(className, true, classLoader);
237        } catch (ClassNotFoundException ex) {
238            throw new RuntimeException(
239                    "Missing class when invoking static main " + className,
240                    ex);
241        }
242
243        Method m;
244        try {
                  //"main是寫死的芜抒,Android所有應(yīng)用進程的入口就是android.app.ActivityThread.java中的main方法
245            m = cl.getMethod("main", new Class[] { String[].class });
246        } catch (NoSuchMethodException ex) {
247            throw new RuntimeException(
248                    "Missing static main on " + className, ex);
249        } catch (SecurityException ex) {
250            throw new RuntimeException(
251                    "Problem getting static main on " + className, ex);
252        }
        .......
266        throw new Zygote.MethodAndArgsCaller(m, argv);
267    }

invokeStaticMain主要反射了android.app.ActivityThread.java中的main方法,得到Method對象m托启,為了清除棧幀宅倒,為新創(chuàng)建的進行一個干凈的環(huán)境,最后拋出一個異常Zygote.MethodAndArgsCaller屯耸。這個異常會在ZygoteInit的main中被捕獲拐迁。

  frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
 public static void main(String argv[]) {
       .....
            //1、啟動一個死循環(huán)監(jiān)聽來自Client端的消息
            zygoteServer.runSelectLoop(abiList);
             //2疗绣、關(guān)閉SystemServer的Socket
            zygoteServer.closeServerSocket();
        } catch (Zygote.MethodAndArgsCaller caller) {
             //3线召、這里捕獲這個異常調(diào)用MethodAndArgsCaller的run方法。
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }

捕獲之后多矮,調(diào)用MethodAndArgsCaller的run方法缓淹,終于進入了ActivityThread的main方法了,一個有血有肉的進程就啟動成功了塔逃。

225    public static class MethodAndArgsCaller extends Exception
226            implements Runnable {
227        /** method to call */
228        private final Method mMethod;
229
230        /** argument array */
231        private final String[] mArgs;
232
233        public MethodAndArgsCaller(Method method, String[] args) {
234            mMethod = method;
235            mArgs = args;
236        }
237
238        public void run() {
239            try {
240                mMethod.invoke(null, new Object[] { mArgs });
241            } catch (IllegalAccessException ex) {
242                throw new RuntimeException(ex);
243            } catch (InvocationTargetException ex) {
244                Throwable cause = ex.getCause();
245                if (cause instanceof RuntimeException) {
246                    throw (RuntimeException) cause;
247                } else if (cause instanceof Error) {
248                    throw (Error) cause;
249                }
250                throw new RuntimeException(ex);
251            }
252        }
253    }
254}

進程被創(chuàng)建出來了讯壶,系統(tǒng)中資源和類我們就可以直接使用了,這是怎么回事湾盗?由于Android系統(tǒng)基本所有進程的創(chuàng)建都是交給Zygote進程創(chuàng)建的伏蚊,而進程的fork基于寫時復(fù)制技術(shù),所以Zygote進程啟動時候加載的資源也會被應(yīng)用進程所使用格粪,如下圖躏吊,原來進程中所需要的資源,庫等都是由它老子辦好了帐萎,繼承過來就行比伏。資源的加載過程參考本系列第二篇博客。

Zygote進程fork進程.png

四吓肋、總結(jié)

應(yīng)用進程的創(chuàng)建和System進程的創(chuàng)建基本上一致凳怨,尤其是在fork進程之后的邏輯,是一模一樣的是鬼,不同的是肤舞,System進程是Zygote進程的大兒子,由自己親手創(chuàng)建均蜜,而其他應(yīng)用進程是通過Process.start發(fā)送創(chuàng)建請求李剖,Zygote幫忙創(chuàng)建的。這個過程其實不算復(fù)雜囤耳,創(chuàng)建流程的詳細序列圖如下篙顺。

進程的創(chuàng)建序列圖偶芍,右鍵查看大圖更清晰.png

進程的創(chuàng)建花了四篇的篇幅,從Zygote進程的創(chuàng)建德玫,System進程的創(chuàng)建和啟動匪蟀,在到應(yīng)用進程的創(chuàng)建,到此就結(jié)束了宰僧,下面將會梳理AMS中進程的數(shù)據(jù)結(jié)構(gòu)---ProcessRecord材彪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市琴儿,隨后出現(xiàn)的幾起案子段化,更是在濱河造成了極大的恐慌,老刑警劉巖造成,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件显熏,死亡現(xiàn)場離奇詭異,居然都是意外死亡晒屎,警方通過查閱死者的電腦和手機喘蟆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來夷磕,“玉大人履肃,你說我怎么就攤上這事∽” “怎么了尺棋?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绵跷。 經(jīng)常有香客問我膘螟,道長,這世上最難降的妖魔是什么碾局? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任荆残,我火速辦了婚禮,結(jié)果婚禮上净当,老公的妹妹穿的比我還像新娘内斯。我一直安慰自己,他們只是感情好像啼,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布俘闯。 她就那樣靜靜地躺著,像睡著了一般忽冻。 火紅的嫁衣襯著肌膚如雪真朗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天僧诚,我揣著相機與錄音遮婶,去河邊找鬼蝗碎。 笑死,一個胖子當著我的面吹牛旗扑,可吹牛的內(nèi)容都是我干的蹦骑。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼肩豁,長吁一口氣:“原來是場噩夢啊……” “哼脊串!你這毒婦竟也來了辫呻?” 一聲冷哼從身側(cè)響起清钥,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎放闺,沒想到半個月后祟昭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡怖侦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年篡悟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匾寝。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡搬葬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出艳悔,到底是詐尸還是另有隱情急凰,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布猜年,位于F島的核電站抡锈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏乔外。R本人自食惡果不足惜床三,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望杨幼。 院中可真熱鬧撇簿,春花似錦、人聲如沸差购。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歹撒。三九已至莲组,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間暖夭,已是汗流浹背锹杈。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工撵孤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人竭望。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓邪码,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咬清。 傳聞我的和親對象是個殘疾皇子闭专,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348