Activity启动过程简析

本文主要内容

  • Activity启动流程
  • 进程启动过程
  • 总结

Android应用可被多种方式启动,包括启动服务、activity,接收广播,ContentProvider被查询也会启动应用。如果应用是persitant应用,系统则会自动地去启动它。

本文主要阐述activity的启动,最后是一些总结性的东西。

Activity启动流程

先来看一张流程图:

activity启动的流程非常非常的多,代码阅读比较困难,我们不一一读了,可以跟着这条线,细细推敲,我们只讲几个重点。

其实activity启动的逻辑主要是这几个部分:

  • 权限控制
  • activity启动模式导致的不同activity stack策略
  • 进程启动
  • IPC通信启动activity

权限控制以及启动模式相关内容,本文不深入探讨,进程启动我们下个小节再讲,这里主要阐述下IPC通信启动activity。

如果我们以桌面上启动音乐为例,桌面和音乐分别属于不同的进程,而ams也是跑在系统进程当中的,三个不同进程之间是如何通信的?

桌面调用ContextImpl的startActivity方法,最后将通过ActivityManagerNative.getDefault(),获取AMS的IPC代理,实现与AMS通信。而AMS最后要来启动音乐,则会收到音乐的ApplicationThread的实例,ApplicationThread其实是一个binder对象,AMS就是通过它才能与音乐进程进行通信,最终创建音乐进程,并启动activity。

进程启动

Android中所有apk的进程都是由zygote启动的,zygote中文名为受精卵,它调用linux接口fork,创建进程。

AMS与zygote采用socket进行进程间的通信,实现进程创建。

zygote创建进程的时候,某种程度上是复制,它会创建一个vm实例,其中会包含一些预加载的系统类以及资源,这样能加快或者方便apk调用。

原理图如上,zygote接收socket通信的指令并读取,然后fork一个VM实例出来,创建新进程并执行这个进程。

既然是socket通信,必然会有一个服务端,android中这个服务端是ZygoteInit,我们来看它的main方法:

public static void main(String argv[]) {
    try {
        // Start profiling the zygote initialization.
        SamplingProfilerIntegration.start();

        boolean startSystemServer = false;
        //注意,zygote这是服务端的名字,类似于java上socket中的端口号,接下来会用到
        String socketName = "zygote";
        String abiList = null;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }

        if (abiList == null) {
            throw new RuntimeException("No ABI list supplied.");
        }
        //使用socket名字,来创建socket服务端
        registerZygoteSocket(socketName);
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
            SystemClock.uptimeMillis());
        preload();
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
            SystemClock.uptimeMillis());

        // Finish profiling the zygote initialization.
        SamplingProfilerIntegration.writeZygoteSnapshot();

        // Do an initial gc to clean up after startup
        gcAndFinalize();

        // Disable tracing so that forked processes do not inherit stale tracing tags from
        // Zygote.
        Trace.setTracingEnabled(false);

        if (startSystemServer) {
            startSystemServer(abiList, socketName);
        }

        Log.i(TAG, "Accepting command socket connections");
        //runSelectLoop方法中是一个死循环,不停地接收指令并fock进程
        runSelectLoop(abiList);

        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    } catch (RuntimeException ex) {
        Log.e(TAG, "Zygote died with exception", ex);
        closeServerSocket();
        throw ex;
    }
}

由代码可知,和java类似,声明socket服务端的端口号并且采用死循环,读取客户端指令并执行。

AMS在startProcessLocked方法中调用Process.start方法,来启动进程,具体流程如下所示:

注意:Process类作为客户端,而ZygoteInit作为服务端,ZygoteInit中的runSelectLoop方法一直死循环,当接到Process创建进程指令时,就会去调用ZygoteConnection的runOnce方法,完成进程创建。

比较有意思的是:

entryPoint = "android.app.ActivityThread";
Process.start(entryPoint ....
public static final ProcessStartResult start(final String processClass,

可以看到Process启动进程的processClass为ActivityThread,而Java语言是在进程启动时执行main方法,所以当apk的进程创建后,第一个被执行的方法就是ActivityThread的main方法。

总结

  • activity的onCreate方法

activity在ActivityThread当中被启动后,由Instrumentation的newActivity方法完成实例创建:

java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
public Activity newActivity(ClassLoader cl, String className,
        Intent intent)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    return (Activity)cl.loadClass(className).newInstance();
}

因为activity类名未知,所以最后创建实例的必是反射创建,而且还要使用正确的ClassLoader。
cl由LoadApk类获取,查看其源码即知,这个ClassLoader是正确的,有点类似于动态加载中指定apk路径构建ClassLoader,它能正确加载到activity。

  • 设计思路

回想activity的创建流程,如果这个工作由我们来做,我们应该要怎么设计它?android为了更为简单易用,将复杂的IPC通信以及其它的都封装得很完美,用户只要声明activity即可,这实在是完美的作品。

其实我们学习过很多的设计模式,但事到临头总是用不出来,有时想想这些常见的流程、机制,都有很多值得我们学习的地方

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

推荐阅读更多精彩内容