應(yīng)用進(jìn)程是如何創(chuàng)建出來(lái)的

簡(jiǎn)介

APP各自運(yùn)行于自己的進(jìn)程中,每一個(gè)進(jìn)程中都擁有一個(gè)獨(dú)立的Dalvik虛擬機(jī)實(shí)例,擁有了Dalvik,Android的Java程序才能運(yùn)行起來(lái)??梢岳斫鉃?,進(jìn)程在以隔離了用戶(hù)環(huán)境下運(yùn)行,使各不干擾。常用的四大組件,要能運(yùn)行起來(lái),首先就需要APP的進(jìn)程已準(zhǔn)備完畢。

本文的目的,是學(xué)習(xí)進(jìn)程是如如何被創(chuàng)建出來(lái)的。

note:源碼版本為8.0,各版本間有差異,但不影響核心設(shè)計(jì)

進(jìn)程啟動(dòng)必要參數(shù)準(zhǔn)備

如在Activity的啟動(dòng)過(guò)程中,當(dāng)AMS發(fā)現(xiàn)此Activity所依賴(lài)的應(yīng)用進(jìn)程還沒(méi)有啟動(dòng)起來(lái),則會(huì)請(qǐng)求Zygote進(jìn)程將此應(yīng)用進(jìn)程啟動(dòng)起來(lái)。
傳送門(mén):Activity啟動(dòng)時(shí)發(fā)生了什么

代碼移步ActivityManagerService.startProcessLocked()

    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
            ......
        try {
            ......
            // 進(jìn)程uid
            int uid = app.uid;
            // GIDS
            int[] gids = null;
            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
            if(!app.isolated){
            ......
                // 記住資源訪(fǎng)問(wèn)權(quán)限
                if (ArrayUtils.isEmpty(permGids)) {
                    gids = new int[3];
                } else {
                    gids = new int[permGids.length + 3];
                    System.arraycopy(permGids, 0, gids, 3, permGids.length);
                }
                gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
                gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
                // shareUserId
                gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
            }
            ......
            // 指明應(yīng)用程序入口
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            if(...){
            
            } else{
                //交給 Zygote 去孵化
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, entryPointArgs);
            }
        } 
    }

代碼總app為ProcessRecord,ProcessRecord描述了一個(gè)進(jìn)程,與進(jìn)程相關(guān)的信息存于ProcessRecord中,AMS也是通過(guò)ProcessRecord才能得知進(jìn)程狀況。

UID

UID標(biāo)識(shí)一個(gè)應(yīng)用進(jìn)程,應(yīng)用程序在安裝時(shí)被分配UID,當(dāng)此應(yīng)用程序續(xù)存期間(沒(méi)卸載),UID不變。普通應(yīng)用程序而言,GID = UID。
通過(guò)命令

adb shell ps | grap packageName

可以查看在運(yùn)行的應(yīng)用程序信息


查看應(yīng)用pid.jpg

圖中APP使用了多進(jìn)程,因此根據(jù)包名查處了兩個(gè)進(jìn)程信息。橫行信息依次為 當(dāng)前用戶(hù)(UID)、進(jìn)程ID(PID)、父進(jìn)程ID(PPID)、進(jìn)程的虛擬內(nèi)存大小、實(shí)際內(nèi)存占用大小、進(jìn)程正在睡眠的內(nèi)核函數(shù)名稱(chēng)。

如所說(shuō),無(wú)論多少次殺掉此APP進(jìn)程再重啟,UID均不變。

GIDS

GIDS則與Application申請(qǐng)的具體權(quán)限有關(guān),申請(qǐng)的相應(yīng)permission被granted時(shí),則有對(duì)應(yīng)的GIDS,因此,GIDS是關(guān)于允許或限制應(yīng)用程序訪(fǎng)問(wèn)設(shè)備資源。比如常在manifest申請(qǐng)?jiān)L問(wèn)網(wǎng)絡(luò)權(quán)限

<uses-permission android:name="android.permission.INTERNET"/>

被允許時(shí),組在GIDS中有相應(yīng)的ID

shareUserId

在GIDS中,shareUserId也比較重要,需簡(jiǎn)單了解沙箱模型。


沙箱模型1.png

各個(gè)應(yīng)用程序運(yùn)行與各自的環(huán)境中(沙箱),默認(rèn)情況下,程序間無(wú)法交互。運(yùn)行在沙箱內(nèi)的應(yīng)用程序如果沒(méi)有被分配權(quán)限,無(wú)法訪(fǎng)問(wèn)系統(tǒng)或資源,因此運(yùn)行去Dalvik虛擬機(jī)的應(yīng)用程序都能得到同樣的安全保護(hù),被限制在各自沙箱內(nèi)的程序互不干涉,使得對(duì)其它或受其它程序的損害降到最低。在沙箱機(jī)制下,應(yīng)用程序間互不信任,相互隔離,各自運(yùn)行。

沙箱模型2.png

通過(guò)shareUserId,可是程序相互信任,公共運(yùn)行與同一進(jìn)程空間內(nèi),可以像訪(fǎng)問(wèn)自有程序一樣訪(fǎng)問(wèn)對(duì)方程序資源。
以上二圖來(lái)源

回到正文,在準(zhǔn)備好啟動(dòng)進(jìn)程的相關(guān)數(shù)據(jù)后,交接給下一節(jié)點(diǎn)繼續(xù)執(zhí)行。還需注意被賦值為“android.app.ActivityThread”的變量entryPoint,后續(xù)會(huì)通過(guò)此變量啟動(dòng)ActivityThread.main(),也就指定了應(yīng)用程序的入口。

啟動(dòng)準(zhǔn)備

此后調(diào)用鏈路為
Process.start()
-> ZygoteProcess.start()
-> ZygoteProcess.startViaZygote()

    private Process.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 invokeWith,
       String[] extraArgs) throws ZygoteStartFailedEx {

        // 存儲(chǔ)啟動(dòng)參數(shù)
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // 以下三參數(shù)必有
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        // 其它參數(shù)看具體情況
        ......
       
        synchronized(mLock) {
            // 獲取LocalkSocket以連接Zygote進(jìn)程,后將參數(shù)通過(guò)LocalSocket
            // 寫(xiě)入Zygote進(jìn)程,讓Zygote進(jìn)程進(jìn)行創(chuàng)建
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
       }

視情況準(zhǔn)備進(jìn)程啟動(dòng)需要的參數(shù),再獲取用以和進(jìn)程進(jìn)行連接的ZygoteState,便可以向Zygote進(jìn)程寫(xiě)入此次新建進(jìn)程的請(qǐng)求。

    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                primaryZygoteState = ZygoteState.connect(mSocket);
            } 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 {
                secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
            } 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);
    }

primaryZygoteState 和 secondaryZygoteState 均為 ZygoteState, Android 5.0以后,Android開(kāi)始支持64位編譯,Zygote進(jìn)程也隨之引入了32/64位的區(qū)別。顧名思義,primaryZygoteState為主Zygote,secondaryZygoteState為輔Zygote。至于是32位為主,還是64位輔,就要看具體Zygote文件的配置了。這里以ABI架構(gòu)類(lèi)型為引子,找到合適的ZygoteSate。

如果所查找的ZygoteState未創(chuàng)建或連接狀態(tài)已關(guān)閉,則會(huì)獲取此ZygoteState。
ZYGOTE_SOCKET

        public static ZygoteState connect(String socketAddress) throws IOException {
            DataInputStream zygoteInputStream = null;
            BufferedWriter zygoteWriter = null;
            final LocalSocket zygoteSocket = new LocalSocket();

            try {
                zygoteSocket.connect(new LocalSocketAddress(socketAddress,
                        LocalSocketAddress.Namespace.RESERVED));

                zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

                zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                        zygoteSocket.getOutputStream()), 256);
            } catch (IOException ex) {
                try {
                    zygoteSocket.close();
                } catch (IOException ignore) {
                }

                throw ex;
            }

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

            return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                    Arrays.asList(abiListString.split(",")));
        }

新建的LocalSocket為ZygoteState成員變量,ZygoteState使用的輸入流與輸出流均從LocalSocket拿到。參數(shù)socketAddress為Process創(chuàng)建ZygoteProcess傳入的ZYGOTE_SOCKET,即"zygote"。因此LocalSocket.connect()將與Zygote進(jìn)程中名為“zygote”的Socket進(jìn)行連接。在有了能與Zygote進(jìn)程通信的媒介之后,已可以向Zygote進(jìn)程傳入數(shù)據(jù)或從Zygote進(jìn)程傳輸數(shù)據(jù)。

創(chuàng)建進(jìn)程

回到
-> ZygoteProcess.startViaZygote()
-> zygoteSendArgsAndGetResult()

    private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
            ......
          // 寫(xiě)入啟動(dòng)參數(shù)長(zhǎng)度
            writer.write(Integer.toString(args.size()));
            writer.newLine();
            
            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                // 寫(xiě)入啟動(dòng)參數(shù)
                writer.write(arg);
                writer.newLine();
            }

            writer.flush();

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

            // 拿到進(jìn)程創(chuàng)建的結(jié)果
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        }

通過(guò)輸出流向Zygote進(jìn)程寫(xiě)入啟動(dòng)數(shù)據(jù)后,進(jìn)入阻塞狀態(tài),直到能接受到Zygote進(jìn)程反饋的數(shù)據(jù)。拿到了創(chuàng)建的結(jié)果,意味著進(jìn)程創(chuàng)建的結(jié)束。

進(jìn)程創(chuàng)建,簡(jiǎn).png

目前來(lái)看,Process通過(guò)LocalSocket與Zygote進(jìn)程進(jìn)行通信,傳輸關(guān)鍵數(shù)據(jù)即可創(chuàng)建進(jìn)程,因此還可對(duì)Zygote如何創(chuàng)建進(jìn)程加以了解。

Zygote進(jìn)程

簡(jiǎn)要了解一下Zygote進(jìn)程的創(chuàng)建,見(jiàn)ZygoteInit.main()

   public static void main(String argv[]) {
        // 創(chuàng)建ZygoteServer
        ZygoteServer zygoteServer = new ZygoteServer();
        ......
        try{
        ......
        // 注冊(cè)名為 "zygote的socket"
        zygoteServer.registerServerSocket(socketName);
        ......
        // 接收請(qǐng)求
        zygoteServer.runSelectLoop(abiList);
        ......
        }
   }

在Zygote進(jìn)程創(chuàng)建時(shí),向ZygoteServer注冊(cè)一個(gè)名為"zygote"的服務(wù)端Socket,之前所說(shuō)的新建進(jìn)程請(qǐng)求到來(lái)時(shí),即是與此Socket進(jìn)行通信。當(dāng)請(qǐng)求到來(lái),在zygoteServer.runSelectLoop()處接收請(qǐng)求。

    void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
        ......
        boolean done = peers.get(i).runOnce(this);
    }

實(shí)際由ZygoteConnection.runOnce()進(jìn)程處理

    boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
        
        try {
            // 獲取LocalSocket傳來(lái)的啟動(dòng)參數(shù)
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        }
        ......
        tyr{
            // 解析參數(shù)
            parsedArgs = new Arguments(args);
            ......
            // frok()
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        }
        ......
        try{
            // pid = 0 說(shuō)明創(chuàng)建了進(jìn)程
            if (pid == 0) {
                // in child
                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                return true;
            }
        }

在接收并解析出LocalSocket所傳輸過(guò)來(lái)的啟動(dòng)參數(shù)后,通過(guò)Zygote.forkAndSpecialize()讓native真正fork()出進(jìn)程。當(dāng)PID = 0 時(shí),說(shuō)明Zygote進(jìn)程創(chuàng)建出了子進(jìn)程。

當(dāng)前情況下,需要Zygote進(jìn)程孵化出的進(jìn)程。Zygote進(jìn)程作為Android進(jìn)程的母體,包含各應(yīng)用進(jìn)程所需要的進(jìn)程信息和資源信息,因從從Zygote進(jìn)程fork()出的子進(jìn)程具有Zygote進(jìn)程信息如數(shù)據(jù)段、代碼段等,自然也包括Dalvik虛擬機(jī)實(shí)體。

在進(jìn)程創(chuàng)建完后,由
ZygoteConnection.handleChildProc()
-> ZygoteInit.zygoteInit() 處理進(jìn)一步事宜

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

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

        RuntimeInit.commonInit();
        // 創(chuàng)建Binder線(xiàn)程池
        ZygoteInit.nativeZygoteInit();
        // 當(dāng)AMS要求新創(chuàng)建線(xiàn)程時(shí),喚醒ActivityThread.main()
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

applicationInit()通過(guò)反射喚醒ActivityThread.main(),之前在AMS請(qǐng)求啟動(dòng)新進(jìn)程時(shí)特意調(diào)到的entryPoint,也一并通過(guò)LocalSocket作為參數(shù)之一傳入Zygote進(jìn)程,因此在這里可以知道此喚醒信息。

AMS在請(qǐng)求啟動(dòng)新進(jìn)程的同時(shí),不會(huì)一直等待進(jìn)程創(chuàng)建,延遲發(fā)送消息PROC_START_TIMEOUT_MSG,如果進(jìn)程為內(nèi)在PROC_START_TIMEOUT_MSG時(shí)間內(nèi)成功創(chuàng)建,則AMS會(huì)認(rèn)為進(jìn)程啟動(dòng)失敗。因此在,在喚醒ActivityThread.main()后attach()時(shí)機(jī),會(huì)通知AMS取消PROC_START_TIMEOUT_MSG消息,以后保證后續(xù)流程進(jìn)行。

至此,也就了解了進(jìn)程時(shí)如何被創(chuàng)建出來(lái)。

總結(jié)

進(jìn)程創(chuàng)建,完整.png

進(jìn)程創(chuàng)建如下:
1、AMS啟動(dòng)各類(lèi)組件發(fā)現(xiàn)相應(yīng)進(jìn)程沒(méi)有啟動(dòng)起來(lái)時(shí),獲取進(jìn)程啟動(dòng)所需參數(shù),通過(guò)Process.start()請(qǐng)求啟動(dòng)進(jìn)程。
2、Process通過(guò)LocalSocket與Zygote進(jìn)程通信,Zygote進(jìn)程對(duì)應(yīng)Socket為"zogote",在Zygote進(jìn)程創(chuàng)建時(shí)啟動(dòng)。
3、ZygoteServer收到啟動(dòng)進(jìn)程請(qǐng)求后,由ZygoteConnection.runOnce()進(jìn)行處理,交由native進(jìn)行fork(),在成功創(chuàng)建子進(jìn)程后,喚醒ActivityThread.main()。
4、AMS不會(huì)無(wú)限等待進(jìn)程創(chuàng)建,因此ActivityThread.main()被喚醒后,會(huì)告知AMS取消PROC_START_TIMEOUT_MSG,以能進(jìn)行后續(xù)Business。

參考

淺析Android沙箱模型
Android -- 系統(tǒng)進(jìn)程Zygote的啟動(dòng)分析
Android ABI的淺析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容