Android中AMS的理解与简介

1. AMS功能概述

  • 组件状态管理:包括四大组件的开启,关闭等一系列操作。如startActivity,startActivityAndWait,activityPaused,startService,stopService,removeContentProvider等
  • 组件状态查询:查询组件当前运行等情况。如getCallingActivity,getService等
  • Task相关:包括removeTask,removeSubTask,moveTaskBackwards,moveTaskToFront等

AMS是通过ActivityStack及其他数据结构来记录,管理系统中的Activity及其他组件状态的,并提供查询功能的一个系统服务。

2. AMS7.0和8.0的区别

  • AMS7.0:

    ActivityManager(AM)是一个和AMS相关联的类,它主要对运行中的activity进行管理,这些管理工作并不是由ActivityManager来处理的,而是交由AMS来处理的。ActivityManager中的方法会通过ActivityManagerNative(AMN)的getDefault()来得到ActivityManageProxy(AMP),通过AMP就可以和AMN进行通讯。而AMN是一个抽象类,它将功能交给它的子类AMS来处理,因此AMP就是AMS的代理类。AMS作为系统服务,很多服务是不会暴露给AM的。

    AMS的启动过程会调用Instrumentation.execStartActivities():

           public void execStartActivities(Context who, IBinder contextThread,
                   IBinder token, Activity target, Intent[] intents, Bundle options) {
               execStartActivitiesAsUser(who, contextThread, token, target, intents, options,
                       UserHandle.myUserId());
           }
    

    这里调用execStartActivitiesAsUser():

           public void execStartActivitiesAsUser() {
                   int result = ActivityManagerNative.getDefault()
                       .startActivities();
           }
        
    

    通过ActivityManagerNative.getDefault()获取AMP,那么看一下getDefault():

           private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
               protected IActivityManager create() {
                   //通过ServiceManager获取AMS代理对象
                   IBinder b = ServiceManager.getService("activity");
                   IActivityManager am = asInterface(b);
                   return am;
               }
           };
    

    这里首先通过ServiceManager获取了AMS的代理对象,然后调用了asInterface():

           static public IActivityManager asInterface(IBinder obj) {
               return new ActivityManagerProxy(obj);
           }
    

    可以看到在asInterface里,构造了一个ActivityManagerProxy,并传入了AMS代理对象的引用,那么AMP就持有了具有进程间通讯能力的AMS代理对象,那么它也就具备了进程间通讯的能力。那么继续看它的startActivities():

           public int startActivity() {
               mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
               reply.readException();
               return result;
           }
    

    这里调用了mRemote.transact(),这个mRemote就是传进来的AMS代理对象。调用它的方法实际就是进程间通讯,这时进程就会切换到AMS所在的SystemServer进程。mRemote.transact()经过一系列处理,最终回调到AMS到onTransact():

           public boolean onTransact(){
               switch (code) {
               case START_ACTIVITY_TRANSACTION:
               {
                      //这里其实是在父类AMN中,AMS重写了并调用了onTransact(),最后调用AMS的startActivity()
                   int result = startActivity(app, callingPackage, intent, resolvedType,
                     resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
                   return true;
               }
             }
    
  • AMS8.0:直接采用了AIDL进行通讯

    AMS8.0的启动过程同样是Instrumentation.execStartActivities():

           public void execStartActivities() {
               execStartActivitiesAsUser();
           }
    

    再看execStartActivitiesAsUser():

           public void execStartActivitiesAsUser() {
                   int result = ActivityManager.getService()
                       .startActivities();
           }
    

    可以看到,这里和7.0的区别是这里调用了ActivityManager.getService()

           public static IActivityManager getService() {
               return IActivityManagerSingleton.get();
           }
           private static final Singleton<IActivityManager> IActivityManagerSingleton =
                   new Singleton<IActivityManager>() {
                       @Override
                       protected IActivityManager create() {
                           final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                          //返回一个代理对象。
                           final IActivityManager am = IActivityManager.Stub.asInterface(b);
                           return am;
                       }
                   };
    

    可以看到,这里直接返回了一个AMS代理对象,没有了AMP。

3. AMS的启动过程

Android系统启动过程简述中可知,AMS在SystemServer的main()中启动。看代码:

       public static void main(String[] args) {
           new SystemServer().run();
       }

再看run():

       private void run() {
                             //创建消息Looper
               Looper.prepareMainLooper();
                             //加载动态库
               System.loadLibrary("android_servers");
     
               //创建系统Context
               createSystemContext();
   
               //创建SystemManager
               mSystemServiceManager = new SystemServiceManager(mSystemContext);
                             //启动引导服务
               startBootstrapServices();
                     //启动核心服务
               startCoreServices();
                     //启动其他服务
               startOtherServices();
                     //开启消息循环
               Looper.loop();
           throw new RuntimeException("Main thread loop unexpectedly exited");
       }

可以看到,这里创建了SystemManager,然后在startBootstrapServices()中用SystemManager创建了AMS,看代码:

       private void startBootstrapServices() {
             //创建AMS
           mActivityManagerService = mSystemServiceManager.startService(
                   ActivityManagerService.Lifecycle.class).getService();
}

可以看到这里调用了SystemManager.startService(),并传入了ActivityManagerService.Lifecycle来创建AMS,看代码:

       public <T extends SystemService> T startService(Class<T> serviceClass) {
                              //通过反射的方式创建service,并调用了构造方法
               Constructor<T> constructor = serviceClass.getConstructor(Context.class);
               service = constructor.newInstance(mContext);
                           //调用startService
               startService(service);
               return service;
       }

这里首先通过反射的方式创建了service,并调用了它的构造,最后调用()。startService0这个serviceClass是传进来的ActivityManagerService.Lifecycle,看一下这个类:

       public static final class Lifecycle extends SystemService {
           private final ActivityManagerService mService;
                
           public Lifecycle(Context context) {
               super(context);
                 //在构造里创建AMS
               mService = new ActivityManagerService(context);
           }
   
           @Override
           public void onStart() {
                 //调用AMS的start()
               mService.start();
           }
                 //返回AMS
           public ActivityManagerService getService() {
               return mService;
           }
       }

可以看到构造里构造了AMS。那么再看上一步的startService()

       public void startService(@NonNull final SystemService service) {
           //将创建的service保存到ArrayList类型的mServices中,完成注册
           mServices.add(service);
             //调用ActivityManagerService.Lifecycle的onStart()
           service.onStart();
      }

这里传入的service就是AMS,将它保存到ArrayList类型的mServices中完成注册,最后调用了service.onStart(),从上一步可知,最后调用的是AMS的start()。同样从上一步可知getService()也返回的是构造的AMS。

那么到这里AMS就启动并且返回了。

4. AMS与应用程序进程

  • 启动应用程序进程时AMS会通过进程名和uid查询这个进程是否存在
  • 如果应用程序进程不存在,则AMS就会请求Zygote进程创建需要的应用程序进程

5. AMS中重要的数据结构

  • ActivityRecord:记录了Activity的所有信息,因此它用来描述一个activity。它是在activity启动时被创建的,具体是在ActivityStarter的startActivity()中被创建的。它存储的信息主要包括以下内容:
    • service:AMS的引用
    • info:ActivityInfo,Activity中代码和AndroidManifest设置的节点信息,如launchMode
    • launcherFromPackage:启动activity的包名
    • taskAffinity:activity希望归属的栈
    • task:TaskRecord,Activity所在的TaskRecord
    • app:ProcessRecord,ActivityRecord所在的应用程序进程
    • state:ActivityState,当前activity的状态
    • icon:Activity的图标资源和标致符
    • theme:Activity的主题资源标识符
  • TaskRecord:用来描述一个Activity任务栈
    • taskId:任务栈的唯一标识符
    • affinity:任务栈的倾向性
    • Intent:启动这个activity的intent
    • mActivites:ArrayList<ActivityRecord>,按照历史顺序排列的Activity记录
    • mStack:ActivityStack,当前归属的ActivityStack
    • mService:AMS的引用
  • ActivityStack:用来管理系统所有的Activity,内部维护了Activity的所有状态,特殊状态的Activity以及和Activity相关的列表等数据。

6. Activity栈管理

Activity是放入Activity任务栈中的,有了任务栈,系统和开发者就能更好地应用和管理Activity,来完成各种业务逻辑

  • Activity任务栈模型

    Activity任务栈由多种数据结构共同组合而成。其中ActivityRecord用来记录一个Activity的所有信息。一个TaskRecord包含了一个或多个ActivityRecord,TaskRecord用来表示Activity的任务栈。ActivityStack又包含了一个或者多个TaskRecord,它是TaskRecord的管理者。Activity栈管理是建立在Activity栈模型之上的,有了栈管理,就可以对应用程序进行操作,应用程序可以复用自身应用中以及其他应用的Activity,节省资源。

  • Launch Mode:用于设置Activity的启动方式,无论是哪种启动方式,所启动的Activity都会位于Activity的栈顶,主要有4种模式:

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

推荐阅读更多精彩内容