首頁 > 軟體

Android 應用程式的啟動流程範例詳解

2023-03-31 06:00:52

應用程序的啟動流程

本文基於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 應用程式的啟動流程範例詳解的詳細內容,更多關於Android 程式啟動流程的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com