安卓应用启动简介

  1. 安卓系统中,组件,应用,与进程的关系:

    1. 一个组件需要依附于一个应用(其对应Application类必须先初始化,ContentProvider除外,看后面)
    2. 一个应用可以拥有多个进程(其Application对象在每个进程中被初始化一遍)
    3. 一个进程可以承载多个应用 (一个进程可以拥有多个Application对象)
  2. 例子:

    1. 通常情况,一个应用运行与一个进程,对应一个Application对象
    2. 一个应用中,某些组件在注册清单中指定了不同进程,则启动时会将这些组件在对应进程中启动,且在这之前,会在每个对应进程中初始化这个应用的Application对象。
    3. 一个进程承载多个应用,若多个应用指定相同UID,且拥有相同签名,则这些应用可以运作在同一个进程,则每个应用的Application都会在这个进程中初始化
  3. 四大组件的启动都涉及到进程和应用的启动,我们这里以最常见的Activity的启动来解析安卓应用的启动流程,以下是Activity的启动分类:

Activity启动分类.png

四种判断结果分别各举一例情况:

  1. Activity已经以SingleTask,SingleTop,SingleInstance 模式启动,当有其它意图再次启动该Activity 时,不再重复创建实例,当前Activity走onNewIntent方法,获取外部传入的数据,并根据当前Activity所处的情况,走其它生命周期。
  2. Activity以普通启动模式,此情况为一般情况,直接创建Activity实例,并走生命周期。
  3. UserId和签名相同的应用可以运行于同一个进程中,当需要启动应用时,若判断出这个进程已经启动,则在对应进程中,完成应用的Application的实例化和生命周期,再完成Activity的实例化与生命周期。
  4. 在进程也不存在的情况下,则先让进程启动,完成初始化工作,再在进程完成Application的实例化与生命周期,再让后完成Activity的实例化与生命周期。

以下具体分析第四种情况,即需要启动的Activity所需依附的进程未启动

概念明确:

  1. 安卓的四大组件的管理全部由ActivityManagerService(以下简称AMS)及其几个协助类完成,启动Activity时,我们需要向AMS发出我们的启动意图,AMS会解析意图,并作出对应的处理。
  2. Binder作为安卓的IPC机制,其分为C/S两端。Server端接收Client端发过来的数据并作出处理,并返回处理结果。
  3. Binder服务端的对象,当被Binder客户端跨进程调用时,其方法的执行是在Binder线程里。
  4. Binder分为匿名Binder和有名Binder,有名可以直接通过ServiceManager获取,即通过键名查询到对应的Binder。匿名Binder未将自己注册到ServiceManager,所以不能通过键名获取到。
  5. AMS本身为Binder子类,为一个Binder服务端,工作在system_server进程,其在系统启动时将自己注册入ServiceManager,所以其为有名Binder,与服务端对应的客户端BinderProxy对象存在于各个应用进程里,但通常使用其封装类ActivityManagerProxy(AMP),与AMS完成远程调用。
  6. Binder可以通过Binder传递,要使用匿名Binder,需要先利用其它Binder获取到这个匿名Binder,如应用进程就在启动时将自己的匿名Binder ApplicationThread通过AMS/AMP传递给了system_server进程,这样system_server进程就存有了应用进程的Binder客户端,可以通过这个客户端调用应用进程的方法,从而实现对应用的管理。
  7. Instrumentation,用于管理应用程序和系统(主要与应用程序内的Activity)的交互过程,如startActivity时由Instrumentation对象将请求发往AMS,而系统对组件管理通Instrumentation对象实现,如Activity对象创建与生命周期的调用,Instrumentation将在应用初始化时被初始化,每个进程只会存在一个Instrumentation对象,且每个Activity都有此对象的引用,
  8. AMS 对四大组件的管理具体实现是由几个类的协助完成的,ActivityStarter对应Activity,ActiveService 对应service,BroadcastQueue对应Broadcast。与Activity相关还涉及到ActivityStack和ActivityStackSupervisor,负责Activity,Task与Stack管理,Activity启动过程中,AMS,ActivityStarter,ActivityStack,ActivityStackSupervisor需要协同工作,以下我们称这几个类为AMS模块。
  9. ActivityThread,与其内部类ApplicationThread协同,与AMS交互,其mian方法可以理解为应用进程的根方法,进程初始化完成后主线程会进入Looper循环,开始接收ApplicationThread转发过来的消息。
  10. ApplicationThread,Binder子类,匿名Binder,作为Binder服务端,接收AMS发过来的消息,由于服务端的方法在Binder调用时都运行在Binder线程,所以需要再通过Hander转发到主线程中,ApplicationThread接收到的调用都会通过Handler再转到主线程中处理,对应的处理方法都是ActivityThread的方法。

启动流程:

调用流程.png
  1. 从startActivity开始,Activity重写了Context的startActivity方法,但大致流程是不变的,以下为Lancher应用启动一个应用时主线程的调用栈:

    img

    可以看出:

    1. Activity的startActivity走了startActivityForResult方法
    2. startActivityForResult调用了Instrumentation的execStartActivity方法
    3. Instrumentation 最终调用AMP的startActivity,AMP会将Intent传递给AMS,所以现在system_server进程里就会有一个Binder线程会去调用AMS的startActivity 方法,这次调用中做了几件重要的事:
      1. 解析Intent,并根据pkms扫描到的信息,创建对应的ActivityRecord,每一个ActivityRecord对应一个应用进程中的Activity实例,ActivityRecord中还会创建这个Activity对应的唯一的token,其会在Activity创建时被传递给对应的Activity,
      2. 通知WMS,显示startWindow ,即对应应用Activity的主题里面windowBackground对应资源,这个窗口由system_server进程显示,不必等到应用进程启动后再显示,所以其启动速度很快。
      3. 远程调用当前前台Activity的schedulePause方法,对应Activity的主线程会走onPause生命周期。 走完后,其会再通知AMS,它已经走完onPause,AMS开始准备启动目标Activity。
  2. 在ActivityStackSupervisor这个类中,判断出 要启动的Activity所需要的进程还未启动,所以需要先启动其进程:

    1. AMS 通知Zygote 进程启动一个应用进程,这个IPC是socket,Zygote 进程收到消息后fork出一个进程,这个进程就是新的Activity所需依附的应用进程,应用进程被fork出来之后,将AMS传递过来的参数配置给自己,然后就会反射调用ActivityThread的main方法。

    2. 此时AMS对这个新进程还是无感知的,需要新进程主动‘联系’AMS,所以进程进入ActivityThread的main之后,主要做两件事:

      1. 实例化自身,进而实例化其成员变量ApplicationThread(匿名Binder服务端),通过AMP远程调用AMS的attachApplication方法,把自己的ApplicationThread传递给AMS模块,现在AMS就知道新进程已经创建完毕,并得到了其ApplicationThread客户端,可以通过这个Binder远程管理应用进程。

        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // Ignore
        }
        
      2. 调用Looper.prepareMainLooper 准备主线程Looper, Looper.loop() 进入循环,等待外界发来消息,此时,应用的进程初始化算完成,从被fork出来到配置参数,到将自己注册入AMS,再Loop主线程进入循环,等待外部消息。

    3. 启动Application:

      以上完成了应用进程的初始化,AMS模块在收到应用进程发过来消息后,会连续做两件事,应用的启动和组件的启动,这里就是Activity的启动。

      AMS收到应用进程准备完毕的消息后,会通过传递过来的ApplicationThread,调用其bindApplication方法,然后在应用进程中,ApplicationThread将这消息转发给主线程,所以在ActivityThread中会走到handleBindApplication,这个方法里完成:

      1. Application的实例化,在LoadedApk里面完成,并添加到ActivityThead中的Application列表。

        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                initializeJavaContextClassLoader();
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
            }
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;
        
        mInitialApplication = app;
        

        并复制给mInitialApplication,这个变量保存安卓进程中第一个启动的Application,如果多个应用共享进程,那这个变量就是第一个启动的应用的Application

      2. ContentProvider的实例化和onCreate,并注册到AMS

      3. Application的onCreate

    4. Activity的启动

      bindApplication之后,AMS模块接着就会调用realStartActivityLocked,同样是通过ApplicationThread,调用其scheduleLaunchActivity,同样通过Handler转到主线程,调用ActivityThread的handleLaunchActivity 方法,这里这个方法里完成几件事:

      1. Activity的对象创建,通过Instrumentation完成

      2. 调用Activity的attach,这里面会将一个contextImpl对象传递给Activity,Activity本身是ContextWrapper,很多操作是委托给contextImpl完成的,同时还会创PhoneWindow对象作为成员变量

      3. 走生命周期

        if (r.isPersistable()) {
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
            mInstrumentation.callActivityOnCreate(activity, r.state);
        }
        ////////////////////
        if (!r.activity.mFinished) {
            activity.performStart();
        }
        ////////////////////
        performResumeActivity(token, clearHide);
        

        分别会调用Activity的onCreate,onStart,onResume,方法

      4. 将视图添加到WMS

        从PhoneWindow拿到DecorView,调用WindowManager的addView,addView里面会走到WindowManagerGlobal里面,创建ViewRootImpl,完成与WMS的通信,之后开始绘制视图

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

推荐阅读更多精彩内容