Android應(yīng)用框架之應(yīng)用啟動(dòng)過(guò)程詳解
在Android的應(yīng)用框架中,ActivityManagerService是非常重要的一個(gè)組件,盡管名字叫做ActivityManagerService,但通過(guò)之前的博客介紹,我們知道,四大組件的創(chuàng)建都是有AMS來(lái)完成的,其實(shí)不僅是應(yīng)用程序中的組件,連Android應(yīng)用程序本身也是AMS負(fù)責(zé)啟動(dòng)的。AMS本身運(yùn)行在一個(gè)獨(dú)立的進(jìn)程中,當(dāng)系統(tǒng)決定要在一個(gè)新的進(jìn)程中啟動(dòng)一個(gè)Activity或者Service時(shí)就會(huì)先啟動(dòng)這個(gè)進(jìn)程。而AMS啟動(dòng)進(jìn)程的過(guò)程是從startProcessLocked啟動(dòng)的。
1.ActivityManagerService.startProcessLocked
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) { ...... try { int uid = app.info.uid; int[] gids = null; try { gids = mContext.getPackageManager().getPackageGids( app.info.packageName); } catch (PackageManager.NameNotFoundException e) { ...... } ...... int debugFlags = 0; ...... int pid = Process.start("android.app.ActivityThread", mSimpleProcessManagement ? app.processName : null, uid, uid, gids, debugFlags, null); ...... } catch (RuntimeException e) { ...... } } ...... }
可以看到,函數(shù)會(huì)調(diào)用Process.start函數(shù)來(lái)創(chuàng)建一個(gè)進(jìn)程,其中第一個(gè)參數(shù)”android.app.ActivityThread”是需要加載的類,而在完成這個(gè)類的加載之后就會(huì)運(yùn)行ActivityThread.main函數(shù)。
2.Process.start
public class Process { ...... public static final int start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, String[] zygoteArgs) { if (supportsProcesses()) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, zygoteArgs); } catch (ZygoteStartFailedEx ex) { ...... } } else { ...... return 0; } } ...... }
這個(gè)函數(shù)最后會(huì)調(diào)用startViaZygote來(lái)創(chuàng)建進(jìn)程,而Zygote正是Android孵化進(jìn)程的服務(wù),所有的進(jìn)程都是通過(guò)Zygotefork出來(lái)的,所以這里創(chuàng)建進(jìn)程的任務(wù)又落到了Zygote頭上了。
3.Process.startViaZygote
public class Process { ...... private static int startViaZygote(final String processClass, final String niceName, final int uid, final int gid, final int[] gids, int debugFlags, String[] extraArgs) throws ZygoteStartFailedEx { int pid; synchronized(Process.class) { ArrayList<String> argsForZygote = new ArrayList<String>(); // --runtime-init, --setuid=, --setgid=, // and --setgroups= must go first argsForZygote.add("--runtime-init"); argsForZygote.add("--setuid=" + uid); argsForZygote.add("--setgid=" + gid); if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) { argsForZygote.add("--enable-safemode"); } if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) { argsForZygote.add("--enable-debugger"); } if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) { argsForZygote.add("--enable-checkjni"); } if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) { argsForZygote.add("--enable-assert"); } //TODO optionally enable debuger //argsForZygote.add("--enable-debugger"); // --setgroups is a comma-separated list if (gids != null && gids.length > 0) { StringBuilder sb = new StringBuilder(); sb.append("--setgroups="); int sz = gids.length; for (int i = 0; i < sz; i++) { if (i != 0) { sb.append(','); } sb.append(gids[i]); } argsForZygote.add(sb.toString()); } if (niceName != null) { argsForZygote.add("--nice-name=" + niceName); } argsForZygote.add(processClass); if (extraArgs != null) { for (String arg : extraArgs) { argsForZygote.add(arg); } } pid = zygoteSendArgsAndGetPid(argsForZygote); } } ...... }
函數(shù)里面最為重要的工作就是組裝argsForZygote參數(shù),這些參數(shù)將告訴Zygote具體的啟動(dòng)選項(xiàng),例如”–runtime-init”就表示要為新啟動(dòng)的運(yùn)行程序初始化運(yùn)行庫(kù)。然后調(diào)用zygoteSendAndGetPid函數(shù)進(jìn)一步操作。
4.Process.zygoteSendAndGetPid
public class Process { ...... private static int zygoteSendArgsAndGetPid(ArrayList<String> args) throws ZygoteStartFailedEx { int pid; openZygoteSocketIfNeeded(); try { /** * See com.android.internal.os.ZygoteInit.readArgumentList() * Presently the wire format to the zygote process is: * a) a count of arguments (argc, in essence) * b) a number of newline-separated argument strings equal to count * * After the zygote process reads these it will write the pid of * the child or -1 on failure. */ sZygoteWriter.write(Integer.toString(args.size())); sZygoteWriter.newLine(); int sz = args.size(); for (int i = 0; i < sz; i++) { String arg = args.get(i); if (arg.indexOf('\n') >= 0) { throw new ZygoteStartFailedEx( "embedded newlines not allowed"); } sZygoteWriter.write(arg); sZygoteWriter.newLine(); } sZygoteWriter.flush(); // Should there be a timeout on this? pid = sZygoteInputStream.readInt(); if (pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); } } catch (IOException ex) { ...... } return pid; } ...... } 這里的sZygoteWriter
是一個(gè)Socket寫入流,是由openZygoteSocketIfNeeded函數(shù)打開的。而這個(gè)Socket由frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中的ZygoteInit類在runSelectLoopMode函數(shù)偵聽的。這個(gè)類會(huì)返回一個(gè)ZygoteConnection實(shí)例,并執(zhí)行ZygoteConnection的runOnce函數(shù)。
5.ZygoteConnection.runOnce
class ZygoteConnection { ...... boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; try { args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { ...... return true; } ...... /** the stderr of the most recent request, if avail */ PrintStream newStderr = null; if (descriptors != null && descriptors.length >= 3) { newStderr = new PrintStream( new FileOutputStream(descriptors[2])); } int pid; try { parsedArgs = new Arguments(args); applyUidSecurityPolicy(parsedArgs, peer); applyDebuggerSecurityPolicy(parsedArgs); applyRlimitSecurityPolicy(parsedArgs, peer); applyCapabilitiesSecurityPolicy(parsedArgs, peer); int[][] rlimits = null; if (parsedArgs.rlimits != null) { rlimits = parsedArgs.rlimits.toArray(intArray2d); } pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits); } catch (IllegalArgumentException ex) { ...... } catch (ZygoteSecurityException ex) { ...... } if (pid == 0) { // in child handleChildProc(parsedArgs, descriptors, newStderr); // should never happen return true; } else { /* pid != 0 */ // in parent...pid of < 0 means failure return handleParentProc(pid, descriptors, parsedArgs); } } ...... }
真正創(chuàng)建進(jìn)程的代碼在Zygote.forkAndSpecialize,通過(guò)Zygote來(lái)fork出一個(gè)新的進(jìn)程作為應(yīng)用進(jìn)程。fork函數(shù)會(huì)有兩個(gè)返回,其中一個(gè)在父進(jìn)程,一個(gè)在子進(jìn)程,其中自進(jìn)程的進(jìn)程號(hào)會(huì)為0,所以按照上面的代碼,這里會(huì)執(zhí)行handleChildProc。
6.ZygoteConnection.handleChildProc
class ZygoteConnection { ...... private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller { ...... if (parsedArgs.runtimeInit) { RuntimeInit.zygoteInit(parsedArgs.remainingArgs); } else { ...... } } ...... }
因?yàn)樵趧?chuàng)建的時(shí)候傳入了“–runtime-init”,所以這里會(huì)運(yùn)行RuntimeInit.zygoteInit。
public class RuntimeInit { ...... public static final void zygoteInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller { // TODO: Doing this here works, but it seems kind of arbitrary. Find // a better place. The goal is to set it up for applications, but not // tools like am. System.setOut(new AndroidPrintStream(Log.INFO, "System.out")); System.setErr(new AndroidPrintStream(Log.WARN, "System.err")); commonInit(); zygoteInitNative(); int curArg = 0; for ( /* curArg */ ; curArg < argv.length; curArg++) { String arg = argv[curArg]; if (arg.equals("--")) { curArg++; break; } else if (!arg.startsWith("--")) { break; } else if (arg.startsWith("--nice-name=")) { String niceName = arg.substring(arg.indexOf('=') + 1); Process.setArgV0(niceName); } } if (curArg == argv.length) { Slog.e(TAG, "Missing classname argument to RuntimeInit!"); // let the process exit return; } // Remaining arguments are passed to the start class's static main String startClass = argv[curArg++]; String[] startArgs = new String[argv.length - curArg]; System.arraycopy(argv, curArg, startArgs, 0, startArgs.length); invokeStaticMain(startClass, startArgs); } ...... }
這里有兩個(gè)關(guān)鍵的函數(shù)調(diào)用,一個(gè)是zygoteInitNative函數(shù)調(diào)用,一個(gè)是invokeStaticMain函數(shù)調(diào)用,前者就是執(zhí)行Binder驅(qū)動(dòng)程序初始化的相關(guān)工作了,正是由于執(zhí)行了這個(gè)工作,才使得進(jìn)程中的Binder對(duì)象能夠順利地進(jìn)行Binder進(jìn)程間通信,而后一個(gè)函數(shù)調(diào)用,就是執(zhí)行進(jìn)程的入口函數(shù),這里就是執(zhí)行startClass類的main函數(shù)了,而這個(gè)startClass即是我們?cè)赟tep 1中傳進(jìn)來(lái)的”android.app.ActivityThread”值,表示要執(zhí)行android.app.ActivityThread類的main函數(shù)。
7. Zygote.invokeStaticMain
public class ZygoteInit { ...... static void invokeStaticMain(ClassLoader loader, String className, String[] argv) throws ZygoteInit.MethodAndArgsCaller { Class<?> cl; try { cl = loader.loadClass(className); } catch (ClassNotFoundException ex) { ...... } Method m; try { m = cl.getMethod("main", new Class[] { String[].class }); } catch (NoSuchMethodException ex) { ...... } catch (SecurityException ex) { ...... } int modifiers = m.getModifiers(); ...... /* * This throw gets caught in ZygoteInit.main(), which responds * by invoking the exception's run() method. This arrangement * clears up all the stack frames that were required in setting * up the process. */ throw new ZygoteInit.MethodAndArgsCaller(m, argv); } ...... }
從代碼中可以看到,通過(guò)ClassLoader加載對(duì)應(yīng)的android.app.ActivityThread類,然后再獲取到對(duì)應(yīng)的main函數(shù)句柄,最后調(diào)用該類的main函數(shù)。不過(guò)這里的調(diào)用方式比較有意思,不知直接調(diào)用,而是通過(guò)拋出一個(gè)異常。這樣做的方式是為了清空堆棧,讓系統(tǒng)認(rèn)為新進(jìn)程是從ActivityThread的main函數(shù)開始的。
8.ActivityThread.main
public final class ActivityThread { ...... public static final void main(String[] args) { SamplingProfilerIntegration.start(); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); if (sMainThreadHandler == null) { sMainThreadHandler = new Handler(); } ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); if (Process.supportsProcesses()) { throw new RuntimeException("Main thread loop unexpectedly exited"); } thread.detach(); String name = (thread.mInitialApplication != null) ? thread.mInitialApplication.getPackageName() : "<unknown>"; Slog.i(TAG, "Main thread of " + name + " is now exiting"); } ...... }
從這里我們可以看出,這個(gè)函數(shù)首先會(huì)在進(jìn)程中創(chuàng)建一個(gè)ActivityThread對(duì)象,然后進(jìn)入消息循環(huán)中,這樣,我們以后就可以在這個(gè)進(jìn)程中啟動(dòng)Activity或者Service了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 分析Android中應(yīng)用的啟動(dòng)流程
- Android 啟動(dòng)activity的4種方式及打開其他應(yīng)用的activity的坑
- Android應(yīng)用啟動(dòng)另外一個(gè)apk應(yīng)用的方法
- Android優(yōu)化應(yīng)用啟動(dòng)速度
- Android使用Intent啟動(dòng)其他非系統(tǒng)應(yīng)用程序的方法
- android應(yīng)用實(shí)現(xiàn)開機(jī)自動(dòng)啟動(dòng)方法
- 解析android創(chuàng)建快捷方式會(huì)啟動(dòng)兩個(gè)應(yīng)用的問(wèn)題
- 解析Android應(yīng)用啟動(dòng)后自動(dòng)創(chuàng)建桌面快捷方式的實(shí)現(xiàn)方法
- Android筆記之:App應(yīng)用之啟動(dòng)界面SplashActivity的使用
- Android Intent啟動(dòng)別的應(yīng)用實(shí)現(xiàn)方法
相關(guān)文章
Adnroid 自定義ProgressDialog加載中(加載圈)
這篇文章主要介紹了Adnroid 自定義ProgressDialog加載中(加載圈),需要的朋友可以參考下2017-06-06Android獲取系統(tǒng)儲(chǔ)存以及內(nèi)存信息的方法(一)
這篇文章主要為大家詳細(xì)介紹了Android獲取系統(tǒng)儲(chǔ)存以及內(nèi)存信息的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10微信小程序電商常用倒計(jì)時(shí)實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了微信小程序電商常用倒計(jì)時(shí)實(shí)現(xiàn)實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-06-06android 使用 IJKPlayer 播放視頻流的實(shí)現(xiàn)代碼
這篇文章主要介紹了android 使用 IJKPlayer 播放視頻流,這需要借助 IAndroidIO 這個(gè)接口,也可以用于播放本地文件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-11-11Rxjava+Retrofit+Okhttp進(jìn)行網(wǎng)絡(luò)訪問(wèn)及數(shù)據(jù)解析
這篇文章主要介紹了Rxjava+Retrofit+Okhttp進(jìn)行網(wǎng)絡(luò)訪問(wèn)及數(shù)據(jù)解析,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下2022-08-08