亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android應用程序的啟動流程是什么

發布時間:2023-03-30 17:51:39 來源:億速云 閱讀:138 作者:iii 欄目:開發技術

本篇內容介紹了“Android應用程序的啟動流程是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    應用進程的啟動流程

    本文基于Android 11,主要分析應用程序的啟動流程,會直接定位到ActivityStackSupervisor.startSpecificActivity函數開始,因為該函數前面的內容主要在Activity的啟動流程中,可以通過這部分的文章來閱讀。

    看源碼流程,需要戒驕戒躁,心態好。配合源碼使用,建議先收藏,夜深人靜,心血來潮再看。

    通過分析應用進程的啟動流程,可以得到:

    • 在Framework層,現在不止有AMS負責請求Zygote進程創建新進程,還有ATMS、ActivityStarter、ActivityTaskManger、ActivityTaskS在協助分擔一些參數和邏輯的檢查。

    • 每個進程都是通過fork Zygote進程而來,且獲得Java虛擬機。也就是說每一個應用進程都有自己的虛擬機。

    • 應用進程是通過Soket去請求Zygote進程fork自己的。

    • 每個進程都有自己的Binder線程池用于IPC。

    • 每個應用進程的主線程在ActivityThread,其main函數會創建消息循環機制。

    1、ActivityStackSupervisor.startSpecificActivity

    ATMS有一個ProcessMap<WindowProcessController>類型的mProcessNames ,用于存儲封裝了已啟動進程信息ProcessRecord和窗口信息Windows的WindowProcessController實例。WindowProcessController用于協調ActivityManger管理ProcessReocrd和WindwManger管理WIndow和Activity的關系。

    void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);
        boolean knownToBeDead = false;
        if (wpc != null && wpc.hasThread()) {
            realStartActivityLocked(r, wpc, andResume, checkConfig);
            return;
            ...
            knownToBeDead = true;
        }
        r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
        final boolean isTop = andResume && r.isTopRunningActivity();
        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
    }

    這里的mService是ActivityTaskManagerService的實例,通過getProcessController函數獲得當前wpc對象,判斷當前啟動應用進程是否啟動wpc != null && wpc.hasThread(),如果條件成立,則開始真正啟動一個未啟動過的Activity,通過realStartActivityLocked;條件不成立,則調用mService的startProcessAsync啟動當前Activity的所在的進程。即startSpecificActivity函數是啟動進程和啟動Activity的一個分界點。

    2、ATMS.startProcessAsync

    PooledLambda.obtainMessage函數是Lambda的調用方式,表示調用ActivityManagerInternal的startProcess函數,后續則是其參數。并返回一個Message對象,發給Handler類型的mH。

    void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
            String hostingType) {
        final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
                mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
                isTop, hostingType, activity.intent.getComponent());
        mH.sendMessage(m);
    }

    抽象類ActivityManagerInternal的繼承類定義在ActivityManagerService的內部類LocalService。

    public final class LocalService extends ActivityManagerInternal

    3、LocalService.startProcess

    @Override
    public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
            boolean isTop, String hostingType, ComponentName hostingName) {
        startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
                new HostingRecord(hostingType, hostingName, isTop),
                ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
                false /* isolated */, true /* keepIfLarge */);  
    }

    4、startProcessLocked函數

    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
                hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
                keepIfLarge, null /* ABI override */, null /* entryPoint */,
                null /* entryPointArgs */, null /* crashHandler */);
    }

    5、ProcessList.startProcessLocked

    ProcessList類的startProcessLocked函數,有幾個重載函數,第一個調用。

    在 !isolated,判斷了啟動IntentFlag是否后臺運行,是的話,直接拒絕。否則清理AMS中發生過Crash的進程(當前應用)。

    分析一:創立當前應用進程的描述ProcessRecord。

    判斷當前系統是否啟動完畢,未啟動完畢,將進程信息緩存到AMS的mProcessesOnHold中。

    分析二:調用了另外一個重載函數。

        final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
                boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
                int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
                boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs,
                Runnable crashHandler) {
            long startTime = SystemClock.uptimeMillis();
            ProcessRecord app;
    		//isolated傳遞進來是false,
            if (!isolated) {
    			//從mProcessNames緩存獲取,由于是首次創建,null
                app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
                checkSlow(startTime, "startProcess: after getProcessRecord");
    			//判斷要啟動進程是否后臺運行,直接return null
                if ((intentFlags &amp; Intent.FLAG_FROM_BACKGROUND) != 0) {
                    if (mService.mAppErrors.isBadProcessLocked(info)) {
                        return null;
                    }
                } else {
                    //重置進程的crash狀態,使其處于正常狀態
                    mService.mAppErrors.resetProcessCrashTimeLocked(info);
                    if (mService.mAppErrors.isBadProcessLocked(info)) {
                        mService.mAppErrors.clearBadProcessLocked(info);
                        if (app != null) {
                            app.bad = false;
                        }
                    }
                }
            } else {
                app = null;
            }
            ProcessRecord precedence = null;
            if (app != null &amp;&amp; app.pid &gt; 0) {
                if ((!knownToBeDead &amp;&amp; !app.killed) || app.thread == null) {
                    app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
                    return app;
                }
                ProcessList.killProcessGroup(app.uid, app.pid);
                precedence = app;
                app = null;
            }
            if (app == null) {
    			// 分析一、創建新的應用進程描述ProcessRocrd
    			//內部會將自己添加到mProcessNames中
    			app = newProcessRecordLocked(info, processName, isolated, isolatedUid, hostingRecord);
    			if (app == null) {
                    return null;
                }
    			//此時三者都是null
                app.crashHandler = crashHandler;
                app.isolatedEntryPoint = entryPoint;
                app.isolatedEntryPointArgs = entryPointArgs;
                if (precedence != null) {
                    app.mPrecedence = precedence;
                    precedence.mSuccessor = app;
                }
            } else {
                app.addPackage(info.packageName, info.longVersionCode, mService.mProcessStats);
            }
            // If the system is not ready yet, then hold off on starting this
            // process until it is.
            if (!mService.mProcessesReady
                    &amp;&amp; !mService.isAllowedWhileBooting(info)
                    &amp;&amp; !allowWhileBooting) {
                if (!mService.mProcessesOnHold.contains(app)) {
                    mService.mProcessesOnHold.add(app);
                }
                if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
                        "System not ready, putting on hold: " + app);
                checkSlow(startTime, "startProcess: returning with proc on hold");
                return app;
            }
    		分析二:
            final boolean success =
                    startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);
            checkSlow(startTime, "startProcess: done starting proc!");
            return success ? app : null;
        }

    6、ProcessList.startProcessLocked重載

    再次調用另外一個重載函數。

    final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
            int zygotePolicyFlags, String abiOverride) {
        return startProcessLocked(app, hostingRecord, zygotePolicyFlags,
                false /* disableHiddenApiChecks */, false /* disableTestApiChecks */,
                false /* mountExtStorageFull */, abiOverride);
    }

    重載函數,這個重載函數處理邏輯很長,主要給前面創建的ProcessRecord類型的app設置各種屬性。例如外部存儲掛載模式,應用進程運行模式,abi架構等等,其中包括最重要一點就是分析一,確定要啟動進程的的類名:android.app.ActivityThread。分析二,繼續調用重載函數。

        boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
                int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
                boolean mountExtStorageFull, String abiOverride) {
    			...
                app.gids = gids;
                app.setRequiredAbi(requiredAbi);
                app.instructionSet = instructionSet;
                final String seInfo = app.info.seInfo
                        + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
                //分析一:確定要啟動應用程序的類名
                final String entryPoint = "android.app.ActivityThread";
    			//分析二:調用另外一個重載函數
                return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
                        runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
                        instructionSet, invokeWith, startTime);
            } catch (RuntimeException e) {
    		  	...
            }
        }

    重載函數:也是設置一些屬性,然后調用startProcess函數。

     boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
                int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
                String seInfo, String requiredAbi, String instructionSet, String invokeWith,
                long startTime) {
                ...
                final Process.ProcessStartResult startResult = startProcess(hostingRecord,
                        entryPoint, app,
                        uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
                        requiredAbi, instructionSet, invokeWith, startTime);
                handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                        startSeq, false);
               ...
            }
        }

    7、ProcessList.startProcess

    ProcessList類的startProcess函數會根據hostingRecord屬性mHostingZygote判斷走不同的創建分支,前面創建使用默認值,所以走了else分支。通過 Process.start函數創建新的應用進程。

    Process.start的一路調用:

    Process.start=&gt;ZygoteProcess.start=&gt;ZygoteState.start=&gt;ZygoteState.startViaZygote

    8、ZygoteState.startViaZygote

    startViaZygote函數,主要是將傳遞進來的參數拼接成成字符串和收集起來。其中processClass是

    private Process.ProcessStartResult startViaZygote(...)
                                                      throws ZygoteStartFailedEx {
            //根據傳遞進來的參數,拼接成字符串并收集到ArrayList&lt;String&gt;類型argsForZygote
            //將作為新應用程序的主函數的參數
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                              zygotePolicyFlags,
                                              argsForZygote);
    }

    9、ZygoteState.openZygoteSocketIfNeeded

    zygoteSendArgsAndGetResult的第一個參數,調用了openZygoteSocketIfNeeded函數。嘗試建立與Socket的連接(如果之前未建立的話)。我們知道Zygote進程在創建的過程,會調用runSelectLoop函數,創建Server端的Socket,一直等待來自AMS的Client端的Socket創建進程請求。

    private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        try {
        	//建立和Zygote的Socket連接
            attemptConnectionToPrimaryZygote();
    		//匹配abi的架構。在Zygote的創建對應四種模式:32,32_64和64,64_32
    		//32,64
            if (primaryZygoteState.matches(abi)) {
                return primaryZygoteState;
            }
    		//主要架構模式不配,匹配第二種 32_64,64_32
            if (mZygoteSecondarySocketAddress != null) {
                // The primary zygote didn't match. Try the secondary.
                attemptConnectionToSecondaryZygote();
                if (secondaryZygoteState.matches(abi)) {
                    return secondaryZygoteState;
                }
            }
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
        }
        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }

    attemptConnectionToPrimaryZygote函數主要通過底層的LocalSocket創建與Zygote進程的Socket連接,并獲得輸入流zygoteInputStream和輸出流zygoteOutputWriter。

    private void attemptConnectionToPrimaryZygote() throws IOException {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            primaryZygoteState =
                    ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
            maybeSetApiBlacklistExemptions(primaryZygoteState, false);
            maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
        }
    }

    和Zygote進程的Server端Socket建立連接后,就是開始往Socket寫數據了。

    10、attemptZygoteSendArgsAndGetResult

    回到第8步調用了zygoteSendArgsAndGetResult函數,又調用了attemptZygoteSendArgsAndGetResult函數。

    zygoteSendArgsAndGetResult=&gt;attemptZygoteSendArgsAndGetResult

    11、attemptZygoteSendArgsAndGetResult

    到這里,通過Socket的方式向Zygote進程寫進前面拼接好的參數,Zygote在Server端的Socket接收到數據之后,會執行創建動作。在返回的result.pid>=0表示創建成功,并運行在新的進程。

        private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
                ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
            try {
                final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
                final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
                zygoteWriter.write(msgStr);
                zygoteWriter.flush();
                Process.ProcessStartResult result = new Process.ProcessStartResult();
                result.pid = zygoteInputStream.readInt();
                result.usingWrapper = zygoteInputStream.readBoolean();
                if (result.pid &lt; 0) {
                    throw new ZygoteStartFailedEx("fork() failed");
                }
                return result;
            } catch (IOException ex) {
                zygoteState.close();
                Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
                        + ex.toString());
                throw new ZygoteStartFailedEx(ex);
            }
        }

    12、Zygote.main

    在Zygote的啟動流程過程,調用了ZygoteInit的main函數,因為Zygote是通過fork自身來創建其他進程,所以需要根據傳遞進來的參數,進行判斷是啟動什么類型的進程,例如自身isPrimaryZygote=true,或者SystemServer進程。然后通過ZygoteServer.runSelectLoop函數,等待其他進程請求創建新的進程。

        public static void main(String argv[]) {
            ZygoteServer zygoteServer = null;
            Runnable caller;
            try {
            	...
                boolean startSystemServer = false;
                String zygoteSocketName = "zygote";
                String abiList = null;
                boolean enableLazyPreload = false;
                for (int i = 1; i &lt; argv.length; i++) {
                    if ("start-system-server".equals(argv[i])) {
                        startSystemServer = true; //判斷是否SystemServer進程
                    } else if ("--enable-lazy-preload".equals(argv[i])) {
                        enableLazyPreload = true;
                    } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                        abiList = argv[i].substring(ABI_LIST_ARG.length());
                    } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    	//SCOKET_NAME_ARG="--socket-name=",根據參數得到SocketName
                        zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                    } else {
                        throw new RuntimeException("Unknown command line argument: " + argv[i]);
                    }
                }
    		    //PRIMARY_SOCKET_NAME=zygote
                final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
             	gcAndFinalize();
                Zygote.initNativeState(isPrimaryZygote);
                ZygoteHooks.stopZygoteNoThreadCreation();
                zygoteServer = new ZygoteServer(isPrimaryZygote);
                if (startSystemServer) {
                	//啟動SystemServer進程
                    Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                    if (r != null) {
                        r.run();
                        return;
                    }
                }
    		   //循環等待AMS來請求創建新的進程
                caller = zygoteServer.runSelectLoop(abiList);
            } catch (Throwable ex) {
                Log.e(TAG, "System zygote died with exception", ex);
                throw ex;
            } finally {
                if (zygoteServer != null) {
                    zygoteServer.closeServerSocket();
                }
            }
    		//調用新的進程主函數
            if (caller != null) {
                caller.run();
            }
        }

    13、ZygoteServer.runSelectLoo

    這里只關注ZygoteServer.runSelectLoop函數,接受Socket客戶端數據。

     /**
         * Runs the zygote process's select loop. Accepts new connections as
         * they happen, and reads commands from connections one spawn-request's
         * worth at a time.
         */
        Runnable runSelectLoop(String abiList) {
            while (true) {
             	...
                ZygoteConnection connection = peers.get(pollIndex);
                final Runnable command = connection.processOneCommand(this);
    			...
                if (mIsForkChild) {
                    return command;
                }
                ....       
       		}
    	}

    14、ZygoteConnection.processOneCommand

    runSelctLoop主要是從循環中檢測是否有連接建立,建立之后執行ZygoteConnection的processOneCommand函數,并返回一個Runable類型的command對象。

    Runnable processOneCommand(ZygoteServer zygoteServer) {
        ...
        args = Zygote.readArgumentList(mSocketReader);
        //根據參數內容,作其他類型的處理
        ...
        //創建進程,調用底層nativeForkAndSpecialize方法,通過fork當前進程來創建一個子線程。
        pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
                parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
                parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
                parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList,
                parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
        ...
        if (pid == 0) {
            //設置mIsForkChild=true
            zygoteServer.setForkChild();
           //關閉Socket連接
            zygoteServer.closeServerSocket();
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
           //執行子進程內容
            return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
        } 
        ...
    }

    15、handleChildProc

    handleChildProc函數。

    private Runnable handleChildProc(ZygoteArguments parsedArgs,
            FileDescriptor pipeFd, boolean isZygote) {
            ...
            if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mDisabledCompatChanges,
                        parsedArgs.mRemainingArgs, null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mRemainingArgs, null /* classLoader */);
            }
    }

    16、 ZygoteInit.zygoteInit

    public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit();//為新進程創建Binder線程池
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }

    以前還以為每個進程共用一個Binder線程池,現在知道每個進程都有自己的Binder線程池進行IPC。

    17、RuntimeInit.applicationInit

        protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
                String[] argv, ClassLoader classLoader) {
            final Arguments args = new Arguments(argv); 
            return findStaticMain(args.startClass, args.startArgs, classLoader);
        }

    這里的args.startClass就是Socket客戶端傳遞下來的android.app.ActivityThread。

    18、RuntimeInit.findStaticMain

    RuntimeInit.findStaticMain函數主要通過反射創建ActivityThread類的實例,并反射主函數main,然后封裝到MethodAndArgsCaller實例中返回。

    protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        ...
        Class&lt;?&gt; cl = Class.forName(className, true, classLoader);
        Method m = cl.getMethod("main", new Class[] { String[].class });
        ...
        return new MethodAndArgsCaller(m, argv);
    }

    MethodAndArgsCaller類繼承自Runable,并在其run函數,調用主函數方法。

    static class MethodAndArgsCaller 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() {
            ...
            mMethod.invoke(null, new Object[] { mArgs });
            ...
        }
    }

    隨著findStaticMain函數方法棧一路返回到runSelectLoop函數,因為mIsForkChild是true,所以MethodAndArgsCaller對象返回到ZygoteInit的main函數,并賦值給caller變量。main函數最后調用caller的run函數。即執行了ActivityThread的主函數main。

    本來自己還有個疑惑,fork子進程之后,并caller的run函數,已經退出了Zygote進程的runSelectLoop循環等待。怎么繼續去接收AMS新的請求。原來如此,fork子進程后,后續的代碼都運行在了子進程,這里return其實是子進程了。

    一個進程調用fork()函數后,系統先給新的進程分配資源,例如存儲數據和代碼的空間。然后把原來的進程的所有值都復制到新的新進程中,只有少數值與原來的進程的值不同。相當于克隆了一個自己。

    19、進程ActivityThread.main。

    public static void main(String[] args) {
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        Looper.loop();
    }

    ActivityThread的主函數,創建了ActivityThread進程,并啟動了消息循環隊列,代表著當前進程的主線程已啟動。

    知識點

    • fork函數。

    • 通過Socket創建新的進程。

    • Binder機制和應用程序創建的時機。

    • ActivityThread的進程的主線程。

    疑問點

    • 通過Zygote進程fork而來的子進程都會獲得Zygote創建的Java虛擬機,也就是每個應用進程都有自己的Java虛擬機。

    • 每個應用進程都有屬于自己的Binder線程池和消息循環機制。

    • 之所以fork Zygote進程而不是init進程,是避免重復初始化環境資源的加載和虛擬機的創建。

    • 進程的創建之所選擇Socket機制進行,因為Binder機制會導致死鎖,怕父進程binder線程有鎖,然后子進程的主線程一直在等其子線程(從父進程拷貝過來的子進程)的資源,但是其實父進程的子進程并沒有被拷貝過來,造成死鎖,所以fork不允許存在多線程

    “Android應用程序的啟動流程是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    舞钢市| 拜城县| 丰城市| 隆安县| 孝昌县| 白山市| 汉阴县| 小金县| 南澳县| 旌德县| 峨边| 毕节市| 高碑店市| 全南县| 拉孜县| 饶河县| 禹州市| 平果县| 康定县| 高尔夫| 右玉县| 包头市| 上饶市| 南川市| 惠东县| 江都市| 苍南县| 伊通| 托里县| 台南市| 永平县| 开平市| 高邮市| 亚东县| 伊川县| 体育| 田阳县| 乌拉特后旗| 通道| 安图县| 余干县|