Android Framework学习笔记(六)应用程序进程启动过程

}

argsForZygote.add(sb.toString());

}

argsForZygote.add(processClass);

if (extraArgs != null) {

for (String arg : extraArgs) {

argsForZygote.add(arg);

}

}

return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);

}

}

注释1处创建了字符串列表argsForZygote ,并将启动应用进程的启动参数保存在argsForZygote中,例如uid、gid等,这里需要注意processClass = android.app.ActivityThread,后文会用到。

注释2会调用zygoteSendArgsAndGetResult函数,需要注意的是,zygoteSendArgsAndGetResult函数中第一个参数中调用了openZygoteSocketIfNeeded函数,而第二个参数是保存应用进程的启动参数的argsForZygote。

Process#zygoteSendArgsAndGetResult()

private static ProcessStartResult zygoteSendArgsAndGetResult(ZygoteState zygoteState, ArrayList args) throws ZygoteStartFailedEx {

try {

// Throw early if any of the arguments are malformed. This means we can

// avoid writing a partial response to the zygote.

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?

ProcessStartResult result = new 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);

}

}

zygoteSendArgsAndGetResult函数主要做的就是将传入的应用进程的启动参数argsForZygote写入到ZygoteState中,结合上文我们知道ZygoteState其实是由openZygoteSocketIfNeeded函数返回的,那么我们接着来看openZygoteSocketIfNeeded函数。

Process#openZygoteSocketIfNeeded()

private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {

if (primaryZygoteState == null || primaryZygoteState.isClosed()) {

try {

primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET); //1

} catch (IOException ioe) {

throw new ZygoteStartFailedEx(“Error connecting to primary zygote”, ioe);

}

}

if (primaryZygoteState.matches(abi)) {

return primaryZygoteState;

}

// The primary zygote didn’t match. Try the secondary.

if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {

try {

secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET); //2

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

}

在之前讲Zygote进程启动过程时我们得知,在Zygote的main函数中会创建name为“zygote”的Server端Socket。

注释1处会调用ZygoteState的connect函数与名称为ZYGOTE_SOCKET的Socket建立连接,这里ZYGOTE_SOCKET的值为“zygote”。

注释2处如果连接name为“zygote”的Socket返回的primaryZygoteState与当前的abi不匹配,则会连接name为“zygote_secondary”的Socket。这两个Socket区别就是:name为”zygote”的Socket是运行在64位Zygote进程中的,而name为“zygote_secondary”的Socket则运行在32位Zygote进程中。既然应用程序进程是通过Zygote进程fock产生的,当要连接Zygote中的Socket时,也需要保证位数的一致。

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


Socket进行连接成功并匹配abi后会返回ZygoteState类型对象,我们在分析zygoteSendArgsAndGetResult函数中讲过,会将应用进程的启动参数argsForZygote写入到ZygoteState中,这样Zygote进程就会收到一个创建新的应用程序进程的请求,我们回到ZygoteInit的main函数。

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

ZygoteInit#main()

public static void main(String argv[]) {

try {

String socketName = “zygote”;

/*注册Zygote用的Socket/

registerZygoteSocket(socketName); //1

//预加载类和资源

preload(); //2

//启动SystemServer进程

if (startSystemServer) {

startSystemServer(abiList, socketName); //3

}

//监听socket,启动新的应用进程

runSelectLoop(abiList); //4

closeServerSocket();

} catch (MethodAndArgsCaller caller) {

//通过反射调用SystemServer#main()

caller.run();

} catch (RuntimeException ex) {

Log.e(TAG, “Zygote died with exception”, ex);

closeServerSocket();

throw ex;

}

}

注释1处通过registerZygoteSocket函数来创建一个Server端的Socket,这个name为”zygote”的Socket用来等待AMS来请求Zygote来创建新的应用程序进程。

注释2处用来预加载类和资源。

注释3处用来启动SystemServer进程,这样系统的关键服务也会由SystemServer进程启动起来。

注释4处调用runSelectLoop函数来等待AMS的请求。

ZygoteInit#runSelectLoop()

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {

ArrayList fds = new ArrayList();

ArrayList peers = new ArrayList();

fds.add(sServerSocket.getFileDescriptor()); //1

peers.add(null);

while (true) {

StructPollfd[] pollFds = new StructPollfd[fds.size()];

for (int i = 0; i < pollFds.length; ++i) { //2

pollFds[i] = new StructPollfd();

pollFds[i].fd = fds.get(i);

pollFds[i].events = (short) POLLIN;

}

try {

Os.poll(pollFds, -1);

} catch (ErrnoException ex) {

throw new RuntimeException(“poll failed”, ex);

}

for (int i = pollFds.length - 1; i >= 0; --i) { //3

if ((pollFds[i].revents & POLLIN) == 0) {

continue;

}

if (i == 0) {

ZygoteConnection newPeer = acceptCommandPeer(abiList); //4

peers.add(newPeer);

fds.add(newPeer.getFileDesciptor());

} else {

boolean done = peers.get(i).runOnce(); //5

if (done) {

peers.remove(i);

fds.remove(i);

}

}

}

}

}

private static ZygoteConnection acceptCommandPeer(String abiList) {

try {

return new ZygoteConnection(sServerSocket.accept(), abiList);

} catch (IOException ex) {

}

}

注释1处中的sServerSocket就是我们在registerZygoteSocket函数中创建的服务端Socket,调用sServerSocket.getFileDescriptor()用来获得该Socket的fd字段的值并添加到fd列表fds中。接下来无限循环用来等待AMS请求Zygote进程创建新的应用程序进程。

注释2处通过遍历将fds存储的信息转移到pollFds数组中。

注释3处对pollFds进行遍历。

注释4如果i==0则说明服务端Socket与客户端连接上,也就是当前Zygote进程与AMS建立了连接,则通过acceptCommandPeer函数得到ZygoteConnection类并添加到Socket连接列表peers中,接着将该ZygoteConnection的fd添加到fd列表fds中,以便可以接收到AMS发送过来的请求。

注释5如果i的值大于0,则说明AMS向Zygote进程发送了一个创建应用进程的请求,则调用ZygoteConnection的runOnce函数来创建一个新的应用程序进程。并在成功创建后将这个连接从Socket连接列表peers和fd列表fds中清除。

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

ZygoteConnection#runOnce()

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

String args[];

Arguments parsedArgs = null;

FileDescriptor[] descriptors;

try {

args = readArgumentList(); //1

descriptors = mSocket.getAncillaryFileDescriptors();

} catch (IOException ex) {

Log.w(TAG, "IOException on command socket " + ex.getMessage());

closeSocket();

return true;

}

try {

parsedArgs = new Arguments(args);//2

//3

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,

parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,

parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,

parsedArgs.appDataDir);

} catch (ErrnoException ex) {

}

try {

//4

if (pid == 0) {

// in child

IoUtils.closeQuietly(serverPipeFd);

serverPipeFd = null;

handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

return true;

} else {

// in parent…pid of < 0 means failure

IoUtils.closeQuietly(childPipeFd);

childPipeFd = null;

return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);

}

} finally {

IoUtils.closeQuietly(childPipeFd);

IoUtils.closeQuietly(serverPipeFd);

}

}

注释1处调用readArgumentList函数来获取应用程序进程的启动参数。注释2处将readArgumentList函数返回的字符串封装到Arguments对象parsedArgs中。

注释3处调用Zygote的forkAndSpecialize函数来创建应用程序进程,参数为parsedArgs中存储的应用进程启动参数,返回值为pid。

注释4处forkAndSpecialize函数主要是通过fork当前进程来创建一个子进程的,如果pid等于0,则说明是在新创建的子进程中执行的,就会调用handleChildProc函数来启动这个子进程也就是应用程序进程。

ZygoteConnection#handleChildProc()

private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)

throws ZygoteInit.MethodAndArgsCaller {

//1

if (parsedArgs.invokeWith != null) {

WrapperInit.execApplication(parsedArgs.invokeWith,

parsedArgs.niceName, parsedArgs.targetSdkVersion,

VMRuntime.getCurrentInstructionSet(),

pipeFd, parsedArgs.remainingArgs);

} else {

RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,

parsedArgs.remainingArgs, null /* classLoader */);

}

}

}

注释1处由于parsedArgs.invokeWith属性默认为null,最后调用RuntimeInit.zygoteInit函数。

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

RuntimeInit#zygoteInit()

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)

throws ZygoteInit.MethodAndArgsCaller {

if (DEBUG) Slog.d(TAG, “RuntimeInit: Starting application from zygote”);

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “RuntimeInit”);

redirectLogStreams();

commonInit();

nativeZygoteInit(); //1

applicationInit(targetSdkVersion, argv, classLoader); //2

}

注释1处会在新创建的应用程序进程中创建Binder线程池。

注释2处调用了applicationInit函数。

RuntimeInit#applicationInit()

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)

throws ZygoteInit.MethodAndArgsCaller {

// 初始化虚拟机环境

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

VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

final Arguments args;

try {

args = new Arguments(argv);

} catch (IllegalArgumentException ex) {

Slog.e(TAG, ex.getMessage());

// let the process exit

return;

}

// Remaining arguments are passed to the start class’s static main

invokeStaticMain(args.startClass, args.startArgs, classLoader); //1

}

注释1处applicationInit函数中主要调用了invokeStaticMain函数,需要注意的是第一个参数args.startClass,这里指的就是前面赋值的android.app.ActivityThread。

RuntimeInit#invokeStaticMain()

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {

Class<?> cl;

try {

cl = Class.forName(className, true, classLoader); //1

} catch (ClassNotFoundException ex) {

throw new RuntimeException("Missing class when invoking static main " + className, ex);

}

Method m;

try {

// 获取main方法

m = cl.getMethod(“main”, new Class[] { String[].class }); //2

} 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(); //3

if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {

throw new RuntimeException("Main method is not public and static on " + className);

}

/*

  • 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); //4

}

注释1处通过反射来获得android.app.ActivityThread类。

注释2处来获得ActivityThread的main函数。

注释3判断修饰符,必须是static而且必须是public类型。

注释4将找到的main函数传入到MethodAndArgsCaller异常中并抛出该异常。这个异常在ZygoteInit#main()方法中捕获。这么做的作用是清除应用程序进程创建过程的调用栈。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

文末

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家

这里笔者分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

【视频教程】

天道酬勤,只要你想,大厂offer并不是遥不可及!希望本篇文章能为你带来帮助,如果有问题,请在评论区留言。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家

这里笔者分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

[外链图片转存中…(img-GvlYRlPd-1712097694580)]

[外链图片转存中…(img-qsYjXf9y-1712097694581)]

【视频教程】

[外链图片转存中…(img-XvB11Kj5-1712097694581)]

天道酬勤,只要你想,大厂offer并不是遥不可及!希望本篇文章能为你带来帮助,如果有问题,请在评论区留言。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值