zoukankan      html  css  js  c++  java
  • android 系统管理

    原文地址: https://www.cnblogs.com/linjzong/p/4256050.html

    看的框架层相关的概念容易忘记,写个备忘录把理解的重点和遇到的疑惑记下。

    Context:用Android最早接触到的一个类,使用非常非常广泛,在各个地方都要用到,像Toast、Dialog、new TextView()、getResource()之类的,经常就有个参数是Context。刚开始的时候对这个对象很疑惑,翻译过来是"上下文",不好理解。事实上,很多时候我们用到的Context,就是Activity本身。在View中get到的Context,其实就是这个View所处的Activity。Activity继承于ContextThemeWrapper,ContextThemWrapper继承于ContextWrapper,ContextWrapper继承于Context。另外,当使用Service的时候,也有一个Context,这是因为Service是继承于ContextWrapper的,这个Context就是Service本身。还有一个全局的Context:Application。通过getApplicationContext获得。

    ContextImpl:虽然Activity继承于Context类,但是真正执行Context类方法的并不是Activity本身,而是ContextImpl类。该类也是继承于Context类,每个Activity内部都有一个ContextImpl对象,该对象是在Activity创建时创建的。装饰模式。

    ActivityThread:一个非常非常重要的类。这个类管理着一个应用程序的生命周期,是应用程序的入口。每个应用程序对应一个ActivityThread对象,甚至于我们整个Android操作系统,也对应一个ActivityThread对象。同时,Activity、Service、Application都是在此类中创建。

    Binder机制:跨进程通信机制,Android系统的核心所在。最早看到这个概念是在学习利用AIDL实现跨应用分享数据的时候,直到后来看了框架层相关的一些资料后才明白,这玩意在Android中扮演着多么重要的角色。在Android中,每启动一个应用,每打开一个Activity,都需要和Android系统做交互,确切地说,是和Android系统中的各个服务做交互,你的应用的每一步操作,都需要经过这些服务的授权于管理才能正常进行,而这些服务都处于另外一个进程中,通过Binder机制来进行交互。以startActivity为例,在这个过程中,应用程序首先将自己的这一动作通过binder机制传递给了ActivityManagerService(其实是调用了ActivityManagerService的某个方法),ActivityManagerService经过一系列操作后,同意了请求,并且在内部注册了这个要启动的Activity,然后又通过Binder机制调用了ActivtiyThread的创建Activity方法,ActivityThread这才开始实例化Activity类,然后回调这个Activity类的onCreate、onResume之类的接口。由于ActivityManagerService记录了每个启动的Activity,它就可以对整个系统所有的Activity做维护了。

    AMS:ActivityManagerServcie的简称。管理所有Activity的服务,Activity的生命周期通过它来调度。

    WMS:WindowManagerService:管理窗口(View)的服务,界面的绘制通过它调度,事件的触发由它传递给指定View.


    Activity的attach方法:由于Activity实例是通过反射机制动态创建的,它的构造函数并真正进行初始化和赋值操作,而是在创建后通过attach方法进行初始化和必要的赋值操作。

    方法如下

    attach(Context context, ActivityThread aThread,  
                Instrumentation instr, IBinder token, int ident,  
                Application application, Intent intent, ActivityInfo info,  
                CharSequence title, Activity parent, String id,  
                Object lastNonConfigurationInstance,    
                Configuration config)

    该方法是在ActivityThread中调用的,各参数详解如下

    context:ContextImpl实例,前面说过Activity对于Context接口的真正实现都转到内部ContextImpl变量实现,就是在这里赋值。在创建Activity时会同时创建一个ContextImpl实例。

    aThread:每个应用都对应一个ActivityThread实例,这里的aThread就是Activity所处应用对应的ActivityThread实例。由于Activity是在ActivityThread中创建和attach的,这个参数就是this。

    instr:这个类型翻译过来时“检测仪器”,比较难懂是什么意思。但是在startActivity中是通过它来向AMS发送请求的,应该是个工具类,用以应用程序和系统服务的交互,会将其赋值给Activity内部的Instrumentation变量。另外这个变量是其实是ActivityThread的私有变量,实例化ActivityThread时创建的,所以一个应用内所有的Activity都共用一个Instrumentation变量。

    token:IBinder对象,这个是最难理解的一点。如果对Binder机制做过了解的就会知道,IBinder对象实际上是另外一个进程内Binder服务的引用,调用它的方法就等于调用Binder服务的方法,Android系统内的各个Service,如AMS、WindowsManagerService、NotificationSerVice、LocationService等都是这么实现的,统称为服务。但更多时候,Binder机制不用于"服务"这类复杂功能的使用,而仅仅就是为了一个简单的跨进程调用,此处的IBinder对象就是如此。前面说过,startActivity时需要到AMS进行注册,注册成功后AMS该如何通知这个应用的ActivityThread创建Activity呢?实际上,在startActivity时,传递给AMS的参数中就带了一个Binder对象:ApplicationThread。到了AMS端就成了一个IBinder对象,在Activity注册成功之后AMS会调用这个IBinder对象的scheduleLaunchActivity方法,这就相当于调用了应用程序内的ApplicationThread对象的scheduleLaunchActivity方法,该方法会发送一条消息至应用主线程的Handler,Handler将会执行handleLaunchActivity方法,在这过程中执行到ActivityThread的performLaunchActivity方法,在这个方法中进行Activity的创建和赋值工作。此处的token,便是在AMS端创建的一个Binder对象的引用,注意它不是AMS这个服务的引用,而是AMS为每个注册的Activity单独创建的Binder对象,类型为Token,继承于IApplicationToken.Stub,它是在创建ActivityRecord对象时同时创建的,看名字就知道ActivityRecord对应于一个Activity的记录。这个token对象有什么用呢?更多时候,它是作为查找ActivityRecord的键存在的,token/ActivityRecord作为键值对保存在AMS中。另外,在源码中这个变量的注释是:window manager token。可能还有个用途是用以和WindowManagerService通信用的,之后看到WindowManagerService相关内容后再补充。用途补充:由于AMS需要管理Activity,正常的做法是把每创建一个Activity就把它的引用传到AMS中,而使用token相当于是通过token进行管理,因为每个token对应了一个Activity,就不需要传Activity过来了。

    ident:本质是AMS端调用了 System.identityHashCode(r),r为ActivityRecord对象,通过内存地址获取hash值。这个对象是干什么用的,暂时没看到,之后补充。

    application:应用对应的application。这个很简单,也经常用到,Activity的getApplication方法获取的就是这个值,同样的,一个应用只有一个application对象,不同Activity内的application对象是同一个。

    intent:虽然这个intent是从ActivityManagerServcie端传过来的,但是它的值应该就是startActivity时的值。注意,在AMS端进行了new Intent(r.intent)的重新实例化,并不是同一个。

    info:ActivityInfo对象,由AMS传递过来,是在AndroidManifest.xml文件中描述Activity节点的内容,对于AndroidManifest文件的解析AMS服务端而不是应用这边。包含主题、载入方式之类的一系列配置内容。用处嘛,比方说主题,在设置ContentView的时候就有用了。

    title:Activity标题。这是在应用端获取的,通过Activityinfo对象调用PackageManager进行获取。

    parent:查了半天没弄清这玩意究竟干什么用,因为在正常的startActivity过程中,parent参数即不在AMS端赋值,也不在应用端赋值,后来全局搜索了一下发现它只在一个startActivityNow方法中进行赋值,上stackoverflow上一查,原来是早期使用TabActivity时用到的,TabActivity内部的Activity的这个变量拥有值,指向TabActivity。同时,内部Activity的启动是不经过Ams的。该技术现在已被淘汰,可以不关注这个变量的使用。

    id:这个同上,也是在TabActivity中使用的,用以表面在TabActivity中该Activity的独有ID。

    lastNonConfigurationInstances:这个也同上,也是TabActivity中用的,我就没查具体用途了。

    config: Configuration config = new Configuration(mCompatConfiguration);通过ActivityThread的mCompatConfiguration对象进行赋值,可以认为所有一个应用内Activity的config 值是相同的。Configuration对象记录了手机的硬件配置类型,如键盘类型、是否触屏。


    ASM端的数据模型和应用端(ActivityThread)的数据模型的对应关系:

    所谓的Android四大组件:Activity、Service、Broadcast Receiver、Content Provider其实都是在AMS进行管理的,AMS是个非常非常重要的服务,之后需要慢慢读懂其工作原理。

    Activity相关数据模型:在AMS端以ActivityRecord类型保存Activity的数据,同时,Actvity会处于某个Task中,以TaskRecord类型保存Task的数据。需要弄清的一点是,Task是AMS这边的概念,在应用端其实是没有Task的。另外,维护Activity和Task的是一个叫ActivityStack的类,ActivityStackSupervisor类用以管理对ActivityStack类进行操作。在ActivityThread端,用ActivityClientRecord类型保存Activity信息。

    Process:进程,每个ActivityThread对应一个进程,进程同样是在AMS进行管理,使用ProcessRecord类保存进程信息。而在ActivityThread端,使用AppBindData类保存进程信息。

    Service:服务端以ServiceMap保存,通过ActiveServices类管理。待补充。

    先说说Activity栈的概念,顺便理清AMS端管理Activity的方式。

    在Activity和AMS之间有个变量叫ActivityStack,看名字就知道,Activity栈,Activity是存放在这个栈中的,每当有创建新Activity的请求过来,AMS只需解析请求,获取和Activity有关资源后生成ActivityRecord对象后,推给ActivityStack处理就行了。前面说到AMS管理Activity的方式是使用token/ActivityRecord的方式,但实际存储时却是直接使用列表的形式而不是键值对,将所有ActivityRecord以ArrayList<ActivityRecord>的方式存储在ActivityStack中一个叫mLRUActivities的变量中(Android 4.4源码为准,早期是保存在mHistory中)。由于ActivityRecord本身就有一个token变量,因此在通过token查找指定ActivityRecord时只需遍历该列表对比token就行了。另外,还有一个非常重要的概念叫做Task。Task同样是一个栈,它的作用是组织Activity。举例来说,有一个应用A内部为10个Activity,编号A0-A9,Task的作用是组织这10个Actvity的分组,你可以讲A0-A3放置在一个Task中,A4-A9放置在一个Task中,注意,由于Task是个栈,在Task中的Activity是有序的,而且这个分组是动态的,通过startActivity时设置的参数不同,可以实现不同的分组。Task在AMS端对应的数据类型为TaskRecod,由于系统中的Activity会对应多个Task,在ActivityStack中同样有一个ArrayList<TakRecord>类型的列表保存这些Task:mTaskHistory。

    对ActivityTask最疑惑的两点在于:1.系统是如何实现在栈顶Activity的管理?2.Task在管理过程中究竟充当着什么样的角色?

    简单点来理解Android系统的Activity显示逻辑:任何时刻只能有一个Activity处于显示状态,这个Activity就是ActivityStack栈的栈顶Activity。前面说过Activity是以列表的形式保存的,那么这个栈顶Activity是指哪个Activity呢?


    onCreate、onResume、onPause、onStop、onDestroy等生命周期相关函数是如何被回调的。

    Activity的生命周期这个话题都被说烂了,这里说一下这些生命周期函数是如何被回调的。Activity的管理者是AMS,但AMS没法直接回调Activity的各种函数,因为两者处于不同进程而Activity自身并不提供Binder服务。前面说过,AMS管理Activity是通过token对象,但token对象是AMS端自己创建的,应用端的Activity保存着该token对象。在需要的时候,Activity可以主动调用token对象的方法,而AMS却没法回调Activty的方法(即应用端可以主动调用服务端方法,而服务端无法主动调用应用端的Activity的方法)。不过没关系,Activity和AMS之间有个桥梁,那就是ActivityThread。

    ActivityTread同样拥有在应用端维护Activity的作用,当然,它维护的是本应用内的Activity。正如AMS使用token/ActivityRecord键值对保存所有Activity信息,ActivityThread使用token/ActivityClientRecord键值对保存本应用所有的Activity信息。同时,它拥有一个继承于Binder的ApplicationThread对象,为AMS提供跨进程调用服务。由于ActivityThread和AMS使用同一个token对象作为定位Activity信息的键,AMS就能使用token操作指定Activity了。

    因为是学习备忘录性质的随笔,并不打算记下很多本人已经非常理解的内容,有些内容就略过了。

    先说说最简单的onCreate函数是如何被调用的。

    当通过startActivity启动一个Activity时,在AMS注册完Activity信息后,最后会调用ActivityThread的ApplicationThread对象的scheduleLaunchActivity方法,在这一步中会将AMS端传递过来的和该Activity有关的一系列信息,封装成ActivityClientRecord对象r,然后将r作为参数发送一条消息至应用主线程的Handler,Handler将会执行handleLaunchActivity方法,在这过程中执行到ActivityThread的performLaunchActivity方法,在这个方法中进行Activity的初始化工作。在初始化Activity成功后,调用Instrumentation的callActivityOnCreate方法

     mInstrumentation.callActivityOnCreate(activity, r.state);

    该方法最终执行的就是activity的performCreate方法

    activity.performCreate(icicle);

    在performCreate中,直接调用了onCreate了

      final void performCreate(Bundle icicle) {
            onCreate(icicle);
            mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
                    com.android.internal.R.styleable.Window_windowNoDisplay, false);
            mFragments.dispatchActivityCreated();
        }

    需要注意的是,在Activity的onCreate方法中是需要进行一系列操作而且不可省略的,所以我们在重写onCreate方法时不能忘记super.onCreate。

    在onCreate最后会执行这么一步操作

    mCalled = true;

    然后在performLaunchActivity中,会查看mCalled是否已经被变为true了,没改变的话,就表示我们没有重写onCreate,直接抛出异常。

    复制代码
      activity.mCalled = false;
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onCreate()");
                    }
    复制代码

    在执行完callActivityOnCreate方法后,会接着执行

    r.stopped = true;
                    if (!r.activity.mFinished) {
                        activity.performStart();
                        r.stopped = false;
                    }

    即触发了Activity的onStart方法。接着执行这些语句

     if (!r.activity.mFinished) {
                        if (r.state != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                        }
                    }

    这里的r.state由AMS传递而来,我们知道onRestoreInstanceState方法用以在系统回收Activity时保存数据,之后创建时进行恢复,便是在这一步恢复的,而保存数据的工作则是在AMS端完成,具体实现以后看到了再补充。这一步便是触发了onRestoreInstanceState()函数。另外由源码我们也可以发现,onRestoreInstanceState所需的操作其实也可以在onCreate中执行,因为onCreate获取的Bundle跟onRestoreInstanceState获取的Bundle是一致的。

    复制代码
     if (!r.activity.mFinished) {
                        activity.mCalled = false;
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                        if (!activity.mCalled) {
                            throw new SuperNotCalledException(
                                "Activity " + r.intent.getComponent().toShortString() +
                                " did not call through to super.onPostCreate()");
                        }
                    }
    复制代码

    这一步回调了onPostCreate函数,这个函数我们一般不会重写,它是提供给系统应用做最终初始化用的,和onCreate的区别在于执行该函数时,onStart和onRestoreInstanceState已经执行了。

    上述几个回调函数都是在performLaunchActivity方法中完成。

    接着是onResume函数的回调。

     回退一点,前面说到AMS通过Binder机制调用了ActivityThread的scheduleLaunchActivity方法,之后调用了handleLaunchActivity方法,而Activity的初始化工作performLaunchActivity方法便是在handleLaunchActivity方法进行的。在执行完performLaunchActivity后,并会进行Activity类的onResume函数的回调了,在handleResumeActivity中执行。这是情况1,正如我们平时所知道的onCreate之后总会跟着onResume,还有一种情况是Activity已创建情况下触发的onResume回调,它的触发条件就有很多了,比如说,我们finish了一个Activity,使另外一个Activity触发了onResume,还有,当我们从桌面打开点击图标进入已经打开的应用,触发了应用当前Activity的onResume,还有,我们打开了一个已经存在的singInstance的Activity,也会触发onResume。但事实上,所有的onResume操作本质原因只有一个:该Activity处于栈顶了。


    Window与View

    每个Activity在attach方法执行时,即初始化时都会创建一个Phonewindow对象,该对象用以和WindowManager做交互,实现Activity UI的真正绘制和IO事件的接收。Activity继承了Window.Callback接口,用以实现Window对IO事件的回调。同时,前面说过AMS会为每个Activity创建一个ActivityRecord对象并且将Binder对象传递给ActivityThread,在创建Activity时以token命名保存在Activity中,在此,会将token对象保存在PhoneWindow中,用以实现AMS和WMS之间的直接交互。

    维护PhoneWindow的是类型为LocalWindowManager的变量,其内部指向了WindowManagerImpl类的一个静态变量,所以实际上一个应用内的所有Activity都是由同一个WindowManagerImpl进行维护的。该变量同时保存在Activity中。

    Windown用以UI的绘制和IO事件的接收,而绘制的内容正是其内部的DecorView。DecorView继承于FrameLayout,一般来说,DecorView加载的layout会有一个名为title的TextView和名为content的ViewGroup,前者显示Activity的标题后者用以作为加载的布局的容器(setContentView),两者会和DecorView一起保存在PhoneWindow中。DecorView一般在onCreate的setContentView方法中被初始化,但即使未调用setContentView,DecorView还是会被初始化,这个过程延迟到了Activity的handleResumeActivity中,在getDecorView方法内执行。所以即使未调用setContentView,我们还是可以看到Activity内有标题和一个空白界面。


    Activity和AMS通信

    Activity可主动向AMS发起通信,一般是在startActivity时,ActivityManagerNative.getDefault返回AMS的代理接口,直接向AMS发起请求。而AMS要想对指定Activity进行操作,必须通过ActivityThread对象。在应用初始化时,ActivityThread会创建一个ApplicationThread对象,该对象时一个Binder对象,同时通过attachApplication方法将其传递至AMS,AMS将其作为进程信息ProcessRecord的局部变量保存起来,以实现AMS直接对指定进程进行调度。而如StarActivity操作时,也会将ApplicationThread传递给AMS,使AMS可以直接使用该ApplicationThread直接进行调度。注意的是,Activity本身是没有创建Binder对象供AMS进行调度的,必须借助ActivityThread的ApplicationThread对象。相反,AMS为每个Activity创建了一个Binder对象:ActivityRecord,该对象会在ActivityThread创建Activity时保存如Activity中,通过这个对象,就可实现AMS对Activity的识别。

    Activity主动发起通信的目的一般是启动一个新的Activity,而AMS发动通信的原因一般是对Activity的生命周期的调度。

    Activity和WMS通信

    ViewRoot本质就是个Handler,用以在应用端接收WMS的指令时进行异步执行。每个DecorView都关联一个ViewRoot,保存在WindowManagerImpl中。

    Activity(PhoneWindow、DecorView,三者概念相同,因为是一对一关系的,之后用Actvity代指三者)是如何和WMS进行通讯的?通讯的关键在ViewRoot,其内部创建并保存了一个类型为W的变量mWindow,W是一个Binder对象,继承了IWindown接口,之后,ViewRoot会将该对象传送至WMS,如前面所知,只要有了Binder对象,进程间通信就非常简单了。WMS端同时用W对象作为识别Activity的标志。

    那ViewRoot是如何和WMS建立通信的呢?两者是通过一个类型为Session的变量进行联系的。在ViewRoot(看源码发现4.4中已经将该类改名为ViewRootImpl)构造函数中,会通过WindowManagerGlobal.getWindowSession()请求WMS,getWindowSession会调用WMS的openSession方法,最终创建一个Session(Binder类型)对象并且返回。该变量会首先保存在WindowManagerGlobal类的一个静态变量中,之后的请求都将直接返回该静态变量而不是重新请求WMS进行创建,这样确保了一个应用只有一个Session对象。之后,返回的Session保存在ViewRoot中,使用该对象就能直接通信了。(Session对象最终会加入WMS的mSessions队列中,类型为HashSet)

    如此一来,Activity和WMS的双向调用就实现了。这里Activity向WMS的调用一般是进行新建时注册请求(add)、销毁时的移除请求(remove)和UI绘制请求。而WMS对Activity的调用则是Activity的大小、可见性、焦点发生变化时进行通知。

    WMS通信几个重要类型与变量

    以下为AMS在注册Activity时请求WMS进行创建:

    WindowToken:一般来说以token命名的类型都是IBinder类型,不过此处的WindowToken并非如此,实际上它只是对内部保存的token对象的一层封装。它内部最主要的两个变量是IBinder token和AppWindowToken appWindowToken。token就是它实际指向的IBinder对象,而appWindowToken只在当前WindowToken是为一个Activity注册时才有用,其他类型的Window,该对象为空。

    AppWindowToken:该类继承WindowToken,它是专门用于Activity的WindowToken,由AMS发起请求创建。其内部有一个变量IApplicationToken appToken,实际就是指向AMS端的ActivityRecord对象,ActivityRecord继承于IBinder并且实现了IApplicationToken 接口。在实例化该对象时,会同时调用WindowToken的构造函数对token和appWindowToken进行初始化。token对象即为appToken,也就是AMS端的ActivityRecord,而appWindowToken就是自身。

    WMS的内部同样十分复杂,新版的源码中有着许多个数组用以保存不同状态的AppWindowToken,这里使用老版的源码进行理解。

    final HashMap<IBinder, WindowToken> mTokenMap:以IBinder作为键,保存WindowToken,当管理的是Actvity的窗口时,IBinder就是ActivityRecord对象。

     final ArrayList<WindowToken> mTokenList:保存所有的WindowToken对象。

    final ArrayList<AppWindowToken> mAppTokens:保存所有Activity的窗口对象。

    mTokenMap和mTokenList保存的数据是一致的,只不过存储方式不同,mAppTokens是前面两个的子集,只保存Activity的窗口。区别Activity窗口和其他窗口可以看WindowToken对象的appWindowToken变量是否为null。

     以下为Activity视图对象创建完毕后向WMS注册创建
    WindowState:WindowState用以保存窗口信息,在应用端请求添加窗口时创建。内部保存了指向应用端Binder对象的IWindow对象和指向AMS端ActivityRecord的WinowToken对象。注意:Activity窗口的WindowToken对象是在注册Activity时由AMS请求创建的,在创建WindowState时会根据ActivityRecord找到该对象,而普通窗口的WinowToken对象则在创建WindowState时同时创建。

    AMS和WMS通信

    由上可知,AMS在WMS会有一个封装了ActivityRecord的AppWindowToken对象,因此WMS是可以直接和AMS通信的,调度AMS端的指定Activity对象,而AMS却无法调度WMS端的指定窗口对象。


    窗口相关

    WMS管理的是窗口,可以简单地理解成View,对于Activity窗口来说,就是DecorView对象。管理的窗口在WMS端会以WindowState对象存储。

    窗口分三类,通过传递过来的WindowManager.LayoutParams的type变量确认。

    1.Application Window:应用程序窗口,简单理解就是Activity对应的窗口(实际还有个启动窗口,不过是由系统调度的,不需要了解)。

    2.Sub Window:子窗口,比如说,在应用中点击菜单键弹出的菜单,还有自定义的AlertDialog,子窗口的特点是必须依附于一个父窗口,父窗口通常为Application Window。

    3.System Windows:系统窗口,如Toast弹出框,锁屏窗口等,这个是系统管理的,不需要了解。


    Android系统运行总结

    系统启动:

    应用安装:

    应用启动:

    内存回收

  • 相关阅读:
    angular基础
    函数&闭包
    springboot + 拦截器 + 注解 实现自定义权限验证
    idea点击RUN启动报错: Broken configuration due to unavailable plugin or invalid configuration dat
    解决“指定的服务已经标记为删除”问题
    Mybatis中的XML中需要用到的转义符号整理
    springboot 2.0+ 自定义拦截器
    idea中lombok的使用
    springboot集成PageHelper,支持springboot2.0以上版本
    IDEA 修改JSP和后端数据后,页面刷新可以实时更新
  • 原文地址:https://www.cnblogs.com/l-h-h/p/10330957.html
Copyright © 2011-2022 走看看