Android应用程序启动
本文开始的时候,先提一个面试中常问的问题:
- Android应用程序启动的入口到底在哪儿?
你可能会回答:
- 启动Activity的onCreate(...)中?
- Application中的onCreate(...)中?
两样都不是?接下来可能就是一段长时间的沉默,你可以回家了,这个问题很基本,但是不看过源码的人很多都不知道。接下来我们就分析一下Android应用程序的启动流程,告诉你Android应用程序真正的启动入口在什么地方。
一、应用程序进程介绍
一个应用程序的进程名称就是AndroidManifest.xml中定义的标签:
manifest节点中的package标签。
应用程序四要素:
- 有一段程序供其运行
- 拥有专用的系统堆栈空间
- 在内核存在对应的进程控制块
- 拥有独立的用户存储空间
通常情况下,我们开发的一个应用程序至少有一个独立的进程,在这个进程中,我们有独立的存储空间,可以分配一些资源,处理一些特定的事情。
之前的文章
这个创建是怎么个创建法?谁创建?这是我们本章探讨的重点。
二、应用程序创建
当前应用进程不存在,创建进程的起点就是AMS->startProcessLocked(...)
这儿不得不贴一些代码,见谅。
private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { app.pendingStart = true; app.killedByAm = false; app.removed = false; app.killed = false; final long startSeq = app.startSeq = ++mProcStartSeqCounter; app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime); if (mConstants.FLAG_PROCESS_START_ASYNC) { mProcStartHandler.post(() -> { try { synchronized (ActivityManagerService.this) { final String reason = isProcStartValidLocked(app, startSeq); if (reason != null) { app.pendingStart = false; return; } app.usingWrapper = invokeWith != null || SystemProperties.get("wrap." + app.processName) != null; mPendingStarts.put(startSeq, app); } final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); synchronized (ActivityManagerService.this) { handleProcessStartedLocked(app, startResult, startSeq); } } catch (RuntimeException e) { synchronized (ActivityManagerService.this) { mPendingStarts.remove(startSeq); app.pendingStart = false; forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, UserHandle.getUserId(app.userId), "start failure"); } } }); return true; } else { try { final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper, startSeq, false); } catch (RuntimeException e) { app.pendingStart = false; forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false, false, true, false, false, UserHandle.getUserId(app.userId), "start failure"); } return app.pid > 0; } }
代码比较长。核心判断就是当前是异步启动进程吗?当前是异步启动进程。
final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime);
真正核心的调用时这句代码,传入了启动进程必要的参数。其中这个entryPoint是什么?循着调用的路径向上找一下。找上一步调用中发现了:
final String entryPoint = "android.app.ActivityThread";return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime);
这儿赋值为android.app.ActivityThread,接下来看他怎么用。
AMS->startProcess
这里面还分为两种情况,webview_service和其他的情况,普通的应用程序就是其他的情况。直接调用的函数是:
startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, new String[] {PROC_START_SEQ_IDENT + app.startSeq});
Process->start
ZygoteProcess->start
ZygoteProcess->startViaZygote
synchronized(mLock) { return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); }
用一个ArrayList将要用的参数加到列表中。执行openZygoteSocketIfNeeded(...)
ZygoteProcess->openZygoteSocketIfNeeded(...)
ZygoteState->connect(...)
public static ZygoteState connect(LocalSocketAddress address) throws IOException { DataInputStream zygoteInputStream = null; BufferedWriter zygoteWriter = null; final LocalSocket zygoteSocket = new LocalSocket(); try { zygoteSocket.connect(address); zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream()); zygoteWriter = new BufferedWriter(new OutputStreamWriter( zygoteSocket.getOutputStream()), 256); } catch (IOException ex) { try { zygoteSocket.close(); } catch (IOException ignore) { } throw ex; } String abiListString = getAbiList(zygoteWriter, zygoteInputStream); return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter, Arrays.asList(abiListString.split(","))); }
zygoteSocket连接的address是在Porcess中定义的zygoteProcess变量:
public static final String ZYGOTE_SOCKET = "zygote";public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";public static final ZygoteProcess zygoteProcess = new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
两个zygoteSocket服务,当第一个没有连接上,尝试第二个,保证socket通信正常。
创建了名为zygote的socket,此socket与本地的驱动设备/dev/socket/zygote绑定一起,通过LocalSocket找到/dev/socket/目录下的zygote文件,然后与之绑定在一起,连接成功。
其中zygoteInputStream为获取当前Zygote socket的输入流对象,然后定义zygoteWriter的写对象,以便向socket中写入数据。
三、socket接收
Zygote进程启动的时候,会执行一个函数,等待一个名为zygote或者zygote_secondary的socket,执行的函数在ZygoteInit->forkSystemServer(...)
ZygoteInit->forkSystemServer(...)
/* For child process */ if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } zygoteServer.closeServerSocket(); return handleSystemServerProcess(parsedArgs); }
这在创建system_sever进程函数中会执行waitForSecondaryZygote(...)函数。
ZygoteInit->waitForSecondaryZygote
private static void waitForSecondaryZygote(String socketName) { String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ? Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET; ZygoteProcess.waitForConnectionToZygote(otherZygoteName); }
也会连接到这个socket上,然后双方都会连接到socket上,然后会执行
caller = zygoteServer.runSelectLoop(abiList);if (caller != null) { caller.run(); }
启动一个线程专门监听/dev/socket/zygote是否有信息发送,如果有信息发送,则执行ZygoteServer->run()中的:
final Runnable command = connection.processOneCommand(this);
ZygoteConnection->processOneCommand(...)
执行到native层fork一个新的进程,进程名就是传入的pkgName。
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, parsedArgs.instructionSet, parsedArgs.appDataDir);
创建进程成功之后,会进入下面的判断流程:
if (pid == 0) { // in child zygoteServer.setForkChild(); zygoteServer.closeServerSocket(); IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; return handleChildProc(parsedArgs, descriptors, childPipeFd, parsedArgs.startChildZygote); } else { // In the parent. A pid < 0 indicates a failure and will be handled in // handleParentProc. IoUtils.closeQuietly(childPipeFd); childPipeFd = null; handleParentProc(pid, descriptors, serverPipeFd); return null; }
当pid=0,表明是在当前新创建的子进程中执行的,一般就是我们认为的应用程序进程。
ZygoteConnection->handleChildProc(...)
if (parsedArgs.invokeWith != null) { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.remainingArgs); // Should not get here. throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned"); } else { if (!isZygote) { return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); } else { return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); } }
当前传入的invokeWith为null,执行else下面的判断。
ZygoteInit->zygoteInit(...)
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) { RuntimeInit.commonInit(); ZygoteInit.nativeZygoteInit(); return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); }
RuntimeInit->applicationInit(...)
这儿设置了虚拟机的targetSdk以及对大小等等虚拟机设置。
RuntimeInit->findStaticMain(...)
protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<?> cl; try { cl = Class.forName(className, true, classLoader); } catch (ClassNotFoundException ex) { throw new RuntimeException( "Missing class when invoking static main " + className, ex); } Method m; try { m = cl.getMethod("main", new Class[] { String[].class }); } catch (NoSuchMethodException ex) { throw new RuntimeException( "Missing static main on " + className, ex); } catch (SecurityException ex) { throw new RuntimeException( "Problem getting static main on " + className, ex); } int modifiers = m.getModifiers(); if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { throw new RuntimeException( "Main method is not public and static on " + className); } return new MethodAndArgsCaller(m, argv); }
通过classLoader反射调用ActivityThread->main(...)方法,最终的执行在MethodAndArgsCaller静态内部类中执行了反射的调用:
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() { try { mMethod.invoke(null, new Object[] { mArgs }); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException(ex); } } }
四、未决的问题
- Binder线程池什么地方创建的?
- 消息循环什么时候创建的?
这两个问题很重要,没有Binder线程池,那么在此进程空间中,和外部的进程binder调用,就会耗时耗内存,产生很大的性能问题,启动了Binder线程池,可以提升这些问题。同样的,如果没有消息循环,Android基本的运行框架都不存在的,无法处理一个个消息,图形无法展示,事情无法处理。
4.1 Binder线程池创建
ZygoteInit.nativeZygoteInit();
此函数建立Binder线程池。深入看其中的代码调用流程。
4.2 消息循环
ActivityThread->main(...)中执行的有关消息循环的代码如下:
Looper.prepareMainLooper();//......ActivityThread thread = new ActivityThread();thread.attach(false, startSeq);//......Looper.loop();
应用程序进程中创建一个主线程的Looper,启动loop(),开始消息循环机制,我们就可以在进程中处理消息机制了。Android的核心机制就是消息机制。
五、小结
通过上面文章的分析,我们知道了启动一个应用程序进程需要下面的几步:
- zygote进程创建socket监听
- 应用程序需要创建的时候向socket发送数据,带上启动进程所需的必要信息。
- 启动crash log监听handler
- 创建binder线程池
- 开启消息循环机制
- Android应用程序的入口----> ActivityThread->main(...)
更多相关文章
- Android(安卓)7.0 虚拟按键(NavigationBar)源码分析 之 View的创建
- android手把手教你开发launcher(一)(AndroidStudio版)
- 文章关键字 ‘nodpi’
- 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得
- Android官方开发文档Training系列课程中文版:连接无线设备之网络
- Android(安卓)ActivityManagerService(AMS)的进程管理
- Android(安卓)权限控制代码分析
- Android(安卓)— 创建文件及文件夹
- android ContentResolver详解