写点什么

Android 系统揭秘(五)- 应用程序启动

用户头像
Android架构
关注
发布于: 17 小时前

Process 则是调用 ZygoteProcess 来启动


frameworks/base/core/java/android/os/ZygoteProcess.java


public final Process.ProcessStartResult start(final String processClass,final String niceName,int uid, int gid, int[] gids,int debugFlags, int mountExternal,int targetSdkVersion,String seInfo,String abi,String instructionSet,String appDataDir,String invokeWith,String[] zygoteArgs) {try {return startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, mountExternal, targetSdkVersion, seInfo,abi, instructionSet, appDataDir, invokeWith, zygoteArgs);} catch (ZygoteStartFailedEx ex) {Log.e(LOG_TAG,"Starting VM process through Zygote failed");throw new RuntimeException("Starting VM process through Zygote failed", ex);}}


看下 startViaZygote 方法


private Pr


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


ocess.ProcessStartResult startViaZygote(final String processClass,final String niceName,final int uid, final int gid,final int[] gids,int debugFlags, int mountExternal,int targetSdkVersion,String seInfo,String abi,String instructionSet,String appDataDir,String invokeWith,String[] extraArgs)throws ZygoteStartFailedEx {ArrayList<String> argsForZygote = new ArrayList<String>();


// --runtime-args, --setuid=, --setgid=,// and --setgroups= must go firstargsForZygote.add("--runtime-args");argsForZygote.add("--setuid=" + uid);argsForZygote.add("--setgid=" + gid);if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {argsForZygote.add("--enable-jni-logging");}...


synchronized(mLock) {return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);}}


这个方法把参数封成数组,并获取 Zygote 连接,一起发给了 zygoteSendArgsAndGetResult 方法


我们先看下获取 Zygote 连接的 openZygoteSocketIfNeeded 方法


/**


  • Tries to open socket to Zygote process if not already open. If

  • already open, does nothing. May block and retry. Requires that mLock be held.*/@GuardedBy("mLock")private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");


if (primaryZygoteState == null || primaryZygoteState.isClosed()) {try {// 与 Zygote 进程建立连接 primaryZygoteState = ZygoteState.connect(mSocket);} catch (IOException ioe) {throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);}}// 判断 abi 是否匹配 if (primaryZygoteState.matches(abi)) {return primaryZygoteState;}


// 不匹配则尝试 Zygote 辅模式 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {try {secondaryZygoteState = ZygoteState.connect(mSecondarySocket);} catch (IOException ioe) {throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);}}


if (secondaryZygoteState.matches(abi)) {return secondaryZygoteState;}


throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);}


然后看下 zygoteSendArgsAndGetResult 方法


@GuardedBy("mLock")private static Process.ProcessStartResult zygoteSendArgsAndGetResult(ZygoteState zygoteState, ArrayList<String> args)throws ZygoteStartFailedEx {try {


int sz = args.size();for (int i = 0; i < sz; i++) {if (args.get(i).indexOf('\n') >= 0) {throw new ZygoteStartFailedEx("embedded newlines not allowed");}}


final BufferedWriter writer = zygoteState.writer;final DataInputStream inputStream = zygoteState.inputStream;


writer.write(Integer.toString(args.size()));writer.newLine();


for (int i = 0; i < sz; i++) {String arg = args.get(i);writer.write(arg);writer.newLine();}


writer.flush();


// Should there be a timeout on this?Process.ProcessStartResult result = new Process.ProcessStartResult();


result.pid = inputStream.readInt();result.usingWrapper = inputStream.readBoolean();


if (result.pid < 0) {throw new ZygoteStartFailedEx("fork() failed");}return result;} catch (IOException ex) {zygoteState.close();throw new ZygoteStartFailedEx(ex);}}


它会向 ZygoteState 写入数据


android 10 之后则是在 attemptZygoteSendArgsAndGetResult 方法写入


@GuardedBy("mLock")private Process.ProcessStartResult zygoteSendArgsAndGetResult(ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)throws ZygoteStartFailedEx {...String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";


if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) {try {return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);} catch (IOException ex) {Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "


  • ex.getMessage());}}


return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);}


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();


// Always read the entire result from the input stream to avoid leaving// bytes in the stream for future process starts to accidentally stumble// upon.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 接收请求并创建应用程序进程

然后我们分析下 Zygote 接收请求步骤


先看下时序图:



在系统启动一节我们分析了 Zygote 的启动,其中有个 Runnable frameworks/base/core/java/com/android/internal/os/ZygoteInit.java


public static void main(String argv[]) {ZygoteServer zygoteServer = new ZygoteServer();


...final Runnable caller;try {...


String socketName = "zygote";


// 等待 AMScaller = zygoteServer.runSelectLoop(abiList);} catch (Throwable ex) {Log.e(TAG, "System zygote died with exception", ex);throw ex;} finally {zygoteServer.closeServerSocket();}


if (caller != null) {caller.run();}}


runSelectLoop 方法是一个循环器,接收来自 AMS 的消息


frameworks/base/core/java/com/android/internal/os/ZygoteServer.java


Runnable runSelectLoop(String abiList) {ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();


fds.add(mServerSocket.getFileDescriptor());peers.add(null);


while (true) {...for (int i = pollFds.length - 1; i >= 0; --i) {if ((pollFds[i].revents & POLLIN) == 0) {continue;}


if (i == 0) {ZygoteConnection newPeer = acceptCommandPeer(abiList);peers.add(newPeer);fds.add(newPeer.getFileDesciptor());} else {try {ZygoteConnection connection = peers.get(i);final Runnable command = connection.processOneCommand(this);


...} catch (Exception e) {...}}}}}


收到命令时交由 Zygote 连接的 processOneCommand 方法(Android 8.0 为 runOnce)处理,其他版本代码细节有所不同,但流程一样


frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java


Runnable processOneCommand(ZygoteServer zygoteServer) {String args[];Arguments parsedArgs = null;FileDescriptor[] descriptors;


try {// 获取应用启动参数 args = readArgumentList();// Android 10 之后的获取参数代码//args = Zygote.readArgumentList(mSocketReader);descriptors = mSocket.getAncillaryFileDescriptors();} catch (IOException ex) {throw new IllegalStateException("IOException on command socket", ex);}


...// fork 创建应用程序进程 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,parsedArgs.appDataDir);


try {if (pid == 0) {// 子进程 zygoteServer.setForkChild();


zygoteServer.closeServerSocket();IoUtils.closeQuietly(serverPipeFd);serverPipeFd = null;


return handleChildProc(parsedArgs, descriptors, childPipeFd);} else {// 父进程 IoUtils.closeQuietly(childPipeFd);childPipeFd = null;handleParentProc(pid, descriptors, serverPipeFd);return null;}} finally {IoUtils.closeQuietly(childPipeFd);IoUtils.closeQuietly(serverPipeFd);}}


可以看到 Zygote 先获取启动参数,然后通过 fork 创建进程,然后若 pi 返回 0,则开始处理应用程序进程。其中 Android 10 之后通过 Zygote 类获取参数,其他没什么变化


private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,FileDescriptor pipeFd) {...


// End of the postFork event.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);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 {return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,null /* classLoader */);


}}


这个方法 Android 10 之后会有所不同


private Runnable handleChildProc(ZygoteArguments parsedArgs,FileDescriptor pipeFd, boolean isZygote) {...if (parsedArgs.mInvokeWith != null) {....} else {if (!isZygote) {return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mDisabledCompatChanges,parsedArgs.mRemainingArgs, null /* classLoader /);} else {// 跳过启动 Binder 线程池 return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,parsedArgs.mRemainingArgs, null / classLoader */);}}}


接着调用了 ZygoteInit 的 zygoteInit 方法


frameworks/base/core/java/com/android/internal/os/ZygoteInit.java


public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {if (RuntimeInit.DEBUG) {Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");}


Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");RuntimeInit.redirectLogStreams();


RuntimeInit.commonInit();// 创建 Binder 线程池 ZygoteInit.nativeZygoteInit();// 初始化 applicationreturn RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);}


这一步会创建 Binder 线程池,再通知初始化 application frameworks/base/core/java/com/android/internal/os/RuntimeInit.java


protected static Runnable applicationInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {


nativeSetExitWithoutCleanup(true);


VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);


final Arguments args = new Arguments(argv);


Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);


// 调用 main 方法(Android8.0 方法名为 invokeStaticMain)return findStaticMain(args.startClass, args.startArgs, classLoader);}


通过反射调用 main 方法


private static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {Class<?> cl;


try {// android.app.ActivityThreadcl = 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);}


// 清除所有的设置过程需要的堆枝帧,并让 ActivityThread 的 main 方法看起来像是应用程序进程的入口方法 return new MethodAndArgsCaller(m, argv);}


这里的 className 是 android.app.ActivityThread,通过反射调用了 ActivityThread 的 main 方法


frameworks/base/core/java/android/app/ActivityThread.java


public static void main(String[] args) {...// 初始化环境 Environment.initForCurrentUser();


...// 切到主线程 Looper.prepareMainLooper();


// 创建 ActivityThreadActivityThread thread = new ActivityThread();thread.attach(false);


if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}


...Looper.loop();


throw new RuntimeException("Main thread loop unexpectedly exited");}

总结

  • 调用 AMS 的 startProcessLocked 方法,发送启动应用程序进程请求

  • Zygote 接收请求并创建应用程序进程

AMS 发送启动应用程序进程请求

android 8-9 时序图:
android 10-11 时序图:
Zygote 接收请求并创建应用程序进程


后记

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android系统揭秘(五)-应用程序启动