Android开发Android技术知识Android开发经验谈

安卓应用启动简介

2018-07-05  本文已影响45人  许峻华
  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所处的情况,走其它生命周期。

    1. Activity以普通启动模式,此情况为一般情况,直接创建Activity实例,并走生命周期。
    2. UserId和签名相同的应用可以运行于同一个进程中,当需要启动应用时,若判断出这个进程已经启动,则在对应进程中,完成应用的Application的实例化和生命周期,再完成Activity的实例化与生命周期。
    3. 在进程也不存在的情况下,则先让进程启动,完成初始化工作,再在进程完成Application的实例化与生命周期,再让后完成Activity的实例化与生命周期。
  2. 以及具体分析第四种情况,即需要启动的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);
        }
        
上一篇下一篇

猜你喜欢

热点阅读