<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文基於Android 11,主要分析應用程式的啟動流程,會直接定位到ActivityStackSupervisor.startSpecificActivity函數開始,因為該函數前面的內容主要在Activity的啟動流程中,可以通過這部分的文章來閱讀。
看原始碼流程,需要戒驕戒躁,心態好。配合原始碼使用,建議先收藏,夜深人靜,心血來潮再看。
通過分析應用程序的啟動流程,可以得到:
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的一個分界點。
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
@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 */); }
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 */); }
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 & 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 && app.pid > 0) { if ((!knownToBeDead && !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 && !mService.isAllowedWhileBooting(info) && !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; }
再次呼叫另外一個過載函數。
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); ... } }
ProcessList類的startProcess函數會根據hostingRecord屬性mHostingZygote判斷走不同的建立分支,前面建立使用預設值,所以走了else分支。通過 Process.start函數建立新的應用程序。
Process.start的一路呼叫:
Process.start=>ZygoteProcess.start=>ZygoteState.start=>ZygoteState.startViaZygote
startViaZygote函數,主要是將傳遞進來的引數拼接成成字串和收集起來。其中processClass是
private Process.ProcessStartResult startViaZygote(...) throws ZygoteStartFailedEx { //根據傳遞進來的引數,拼接成字串並收集到ArrayList<String>型別argsForZygote //將作為新應用程式的主函數的引數 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), zygotePolicyFlags, argsForZygote); }
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寫資料了。
回到第8步呼叫了zygoteSendArgsAndGetResult函數,又呼叫了attemptZygoteSendArgsAndGetResult函數。
zygoteSendArgsAndGetResult=>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 < 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); } }
在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 < 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(); } }
這裡只關注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; } .... } }
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); } ... }
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 */); } }
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。
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。
RuntimeInit.findStaticMain函數主要通過反射建立ActivityThread類的範例,並反射主函數main,然後封裝到MethodAndArgsCaller範例中返回。
protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { ... Class<?> 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()函數後,系統先給新的程序分配資源,例如儲存資料和程式碼的空間。然後把原來的程序的所有值都複製到新的新程序中,只有少數值與原來的程序的值不同。相當於克隆了一個自己。
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程序,並啟動了訊息迴圈佇列,代表著當前程序的主執行緒已啟動。
以上就是Android 應用程式的啟動流程範例詳解的詳細內容,更多關於Android 程式啟動流程的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45