深入理解Android 卷1:Zygote进入java

1.引言

上节记录到zygote进程的产生哪里,zygote是进入Java层的入口。下面就按照书上,博客上写的,结合源码看看是不是那么回事。最后会打印log看看究竟,个人认为只需要吧每个流程能在大脑中形成一个完整的回路就行,不必搞懂代码的具体实现。

2.app_main.cpp

Zygote相关的代码在app_main.cpp中,按照调用流程,结合源码看一遍是不是那么回事。

app_main.cpp中 int main()方法有一段代码很重要,这段代码就能进入java层。


image.png

AppRuntime 继承AndroidRuntime

image.png

AppRuntime的调用:


image.png

image.png

start方法做了三件事:
1.初始化虚拟机,为进入java层做准备
2.注册jni函数。这句话可能不理解。这么说吧,Android系统本身有很多地方都是采用了jni。最常见
env->FindClass .没有这步注册动作,就没得这个api
3.通过反射调用ZygoteInit.java

初始化jvm

image.png

注册jni函数

image.png

反射调用java代码,进入java世界

image.png

从代码片段可以看出调用的事main方法,且该方法还是一个静态的。进入ZygoteInit看看是否有这个方法。


image.png

看到main()方法的确是有的并且还是一个static。

3.ZygoteInit.java

这个java层入口。按照书上说的,下面标注的是很重要的5个步骤。


image.png

3.1 registerZygoteSocket

image.png

registerZygoteSocket函数,这个函数其实很简单,就是创建了一个服务端的socket,并赋值给全局变量sServerSocket。那么这个服务端的socket具体要接受什么消息?当请求新建一个进程的时候,就会被这个socket接收到请求,然后就被处理。

3.2 preload()

image.png

3.3 gcAndFinalize()

image.png

3.4 startSystemServer

系统初始化到这里之后,系统中已经有3个进程了,最开始的init,zygote和zygote分裂出来的system_server。system_server部门我们以后再看,接着看zygote的执行。

3.5 runSelectLoop

runSelectLoop函数的逻辑比较简单,主要有两点:
1、 处理客户端的连接和请求。其中客户端在zygote进程中使用ZygoteConnection对象表示。
2、 客户的请求有ZygoteConnection的runOnce来处理。


image.png

4 SystemServer进程的作用

看如下代码:
startSystemServer()中有一个handlerSystemServerProcess()方法。顾名思义处理系统Server过程的方法。ActivityManagerService,WindowManagerService这些服务都是SystemServer进程处理的

handlerSystemServerProcess

image.png

RuntimeInit.zygoteInit()通过抛出异常

image.png

nativeZygoteInit()最后调用的是:

image.png

applicationInit里面有一个invokeStaticMain方法,该方法通过传入的className,反射得到Method,然后抛出异常,其中参数m 就是className的Main方法,并且异常被ZygoteInit.main的catch捕捉到(实际上是android.app.ActivityThread类的main函数)。

ZygoteInit捕捉异常:

image.png

caller.run()通过这种方式间接性的调用了,SystemServer的main函数。

5. 应用打开过程

打开一个应用相当于是开启了一个进程,这个流程是怎样执行的呢?
解析:
ActivityManagerService将请求发送给zygote进程后, 就轮到zygote进程处理消息了。通过分析zygote进程的启动流程,我们已经知道zygote进程收到请求后,将执行ZygoteConnection的runOnce函数。

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    ......
    for (int i = pollFds.length - 1; i >= 0; --i) {
        .........
        if (i == 0) {
            ZygoteConnection newPeer = acceptCommandPeer(abiList);
            peers.add(newPeer);
            fds.add(newPeer.getFileDesciptor());
        } else {
            //处理请求
            boolean done = peers.get(i).runOnce();
            if (done) {
                peers.remove(i);
                fds.remove(i);
            }
        }
    }
    ............
}

接下来,我们看看函数runOnce的实际操作

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    //解析传入的参数
    ........
    try {
        .......
        //与启动SystemServer进程一样,最终也会通过native函数fork,并配置进程的参数
        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) {
        .......   
    } catch (IllegalArgumentException ex) {
        ....... 
    } catch (ZygoteSecurityException ex) {
        ....... 
    }

    try {
        if (pid == 0) {
            // 子进程创建成功
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            //子进程根据参数利用handleChildProc作进一步处理
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

            // should never get here, the child is expected to either
            // throw ZygoteInit.MethodAndArgsCaller or exec().
            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);
    }
}

最后,我们看看handlehandleChildProc:

private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller {
    //关闭fork过来的zygote server socket
    closeSocket();
    ZygoteInit.closeServerSocket();
    //处理参数
    ........
    if (parsedArgs.invokeWith != null) {
      WrapperInit.execApplication(.....)
    } else {
        //完成进程的初始化,然后抛异常
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */);
    }
}

从上面的代码可以看出,函数handleChildProc最终还是会调用Runtime的zygoteInit。
如同SystemServer进程一样,普通进程也会进行一些初始化,建立binder通信后,抛出异常,最终由ZygoteInit.java捕获异常,然后反射启动对应类的main函数(实际上是android.app.ActivityThread类的main函数)。

参考连接:
http://blog.csdn.net/gaugamela/article/details/52261075
http://blog.csdn.net/hu3167343/article/details/38370993
https://www.cnblogs.com/bastard/archive/2012/09/03/2668579.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352