Android应用框架之应用启动过程详解
在android的应用框架中,activitymanagerservice是非常重要的一个组件,尽管名字叫做activitymanagerservice,但通过之前的博客介绍,我们知道,四大组件的创建都是有ams来完成的,其实不仅是应用程序中的组件,连android应用程序本身也是ams负责启动的。ams本身运行在一个独立的进程中,当系统决定要在一个新的进程中启动一个activity或者service时就会先启动这个进程。而ams启动进程的过程是从startprocesslocked启动的。
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) { ...... } } ...... }
可以看到,函数会调用process.start函数来创建一个进程,其中第一个参数”android.app.activitythread”是需要加载的类,而在完成这个类的加载之后就会运行activitythread.main函数。
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; } } ...... }
这个函数最后会调用startviazygote来创建进程,而zygote正是android孵化进程的服务,所有的进程都是通过zygotefork出来的,所以这里创建进程的任务又落到了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); } } ...... }
函数里面最为重要的工作就是组装argsforzygote参数,这些参数将告诉zygote具体的启动选项,例如”–runtime-init”就表示要为新启动的运行程序初始化运行库。然后调用zygotesendandgetpid函数进一步操作。
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
是一个socket写入流,是由openzygotesocketifneeded函数打开的。而这个socket由frameworks/base/core/java/com/android/internal/os/zygoteinit.java文件中的zygoteinit类在runselectloopmode函数侦听的。这个类会返回一个zygoteconnection实例,并执行zygoteconnection的runonce函数。
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); } } ...... }
真正创建进程的代码在zygote.forkandspecialize,通过zygote来fork出一个新的进程作为应用进程。fork函数会有两个返回,其中一个在父进程,一个在子进程,其中自进程的进程号会为0,所以按照上面的代码,这里会执行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 { ...... } } ...... }
因为在创建的时候传入了“–runtime-init”,所以这里会运行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); } ...... }
这里有两个关键的函数调用,一个是zygoteinitnative函数调用,一个是invokestaticmain函数调用,前者就是执行binder驱动程序初始化的相关工作了,正是由于执行了这个工作,才使得进程中的binder对象能够顺利地进行binder进程间通信,而后一个函数调用,就是执行进程的入口函数,这里就是执行startclass类的main函数了,而这个startclass即是我们在step 1中传进来的”android.app.activitythread”值,表示要执行android.app.activitythread类的main函数。
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); } ...... }
从代码中可以看到,通过classloader加载对应的android.app.activitythread类,然后再获取到对应的main函数句柄,最后调用该类的main函数。不过这里的调用方式比较有意思,不知直接调用,而是通过抛出一个异常。这样做的方式是为了清空堆栈,让系统认为新进程是从activitythread的main函数开始的。
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"); } ...... }
从这里我们可以看出,这个函数首先会在进程中创建一个activitythread对象,然后进入消息循环中,这样,我们以后就可以在这个进程中启动activity或者service了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: python3 模拟登录v2ex实例讲解