Android插件化开发之AMS与应用程序(客户端ActivityThread、Instrumentation、Activity)通信模型分析

转载来自:http://blog.csdn.net/qinjuning/article/details/7262769

 今天主要分析下ActivityManagerService(服务端) 与应用程序(客户端)之间的通信模型,在介绍这个通信模型的基础上,再

   简单介绍实现这个模型所需要数据类型。

 

        本文所介绍内容基于android2.2版本。由于Android版本的不同,本文所包含的一些类可能在命名等细节上做了一些更改,但

   万变不离其宗,整个核心思想和通信流程依旧如下。

            例如,①、在android2.3上就将android2.2中ActivityManagerService的很处理逻辑提炼出来,形成了一个单独的

        ActivityStack类,因而显得更“高级”;

                     ②、将后文讲解到的HistoryRecord.Java直接重名名ActivityRecord.java等。

 

             很多不同点我也就不在细说了。大家在研究源码的过程里,注意差异就成。

 

 

       Android的三大核心功能有如下三个:

           1、View.java    关于View工作原理,《Android中View绘制流程以及invalidate()等相关方法分析》分析过。

                   功能有: 绘制图形、处理触摸、按键事件等;

           2、ActivityManagerService.java  简称为 AMS

                   功能有:管理所有应用程序的Activity 、内存管理等 。

           3、WindowManagerService.java 简称为WMS

                   功能有:为所有应用程序分配窗口,并管理这些窗口。

 

 

        从上可知,AMS作为一种系统级服务管理所有Activity,当操作某个Activity时,例如: 启动一个新的Activity、停止当前

    Activity,必须报告给AMS,而不能“擅自处理”。当AMS接受到具体通知时,会根据该通知的类型,首先会更新内部记录,

    然后在通知相应客户进程去运行一个新的Activity或者停止指定的Activity。另外,由于AMS记录了所有Activity的信息,当然

    能够主动的调度这些Activity,甚至在内存不足时,主动杀死后台的Activity。

 

    首先对模型中可能运到的类做一个介绍:

     ActivityThread.java    路径位于:\frameworks\base\core\java\android\app\ActivityThread.java

         说明: 该类为应用程序(即APK包)所对应进程(一个进程里可能有多个应用程序)的主线程类,即我们通常所说的UI线程。

           一个ActivityThread类对应于一个进程。最重要的是,每个应用程序的入口是该类中的static main()函数 。

   

      Activity.java               路径位于:\frameworks\base\core\java\android\app\Activity.java

        说明:该类是与用户交互的对象,同时也是APK应用程序运行的最小单元。ActivityThread类会根据用户的操作选择运行

          哪个Activity。当前运行的Activity是出于resume状态(有且仅有一个),其他Activity出于pause或stop状态。

 

      Instrumentation.java  路径位于 :\frameworks\base\core\java\android\app\ActivityThread.java

         说明: 该类用于具体操作某个Activity的功能----单向(oneway)调用AMS以及统计、测量该应用程序的所有开销。

            一个Instrumentation类对应于一个进程。每个Activity内部都有一个该Instrumentation对象的引用。

 

      举个例子吧。

           我们将我们应用程序比作一个四合院,那么Activity对应于四合院的人,ActivithThread对应于院子的主人----管理所有人,

    Instrumentation对应于管家------受气的命,接受来自人(Activity/ActivithThread)的命令 ,去单向(oneway)调用AMS 。

 

  ApplicationThread类是ActivityThread的内部类:

       说明:该类是一个Binder类,即可实现跨进程通信。主要用于接受从AMS传递过来的消息,继而做相应处理。

 

   ActivityManagerService.java 路径位于:        

                                       \frameworks\base\services\java\com\android\server\am\ActivityManagerService.java

       说明:该类是一个Binder类,即可实现跨进程通信。因此可以接受从客户端,例如Instrumentation、Context等调用过来的

           信息。ActivityManagerService提供了全局的代理对象,供IPC调用。

 

 

  AMS与ActivityThread的通信模型图如下:

从该模型图我们得知以下知识点:

 

       第一、 引起调用AMS的对象通常有Context 、 Instrumentatio、ActivityThread等 。

       第二、当AMS接受到来自某个应用程序传来的消息后,在AMS内部处理完毕后,会通过Binder机制回调回该应用程序

             所在ApplicationThread服务端类,即ActivityThread.java类。

       第三、当ActivityThread接受到AMS传递过来的消息后,进行内部处理。如果需要的话,会继续与AMS通信。

       最后,当整个通信完成时,ActivityThread会选择合适的对象,例如Service、Activity、BroadcastReceiver等去做相应的

            处理。

 

 

 

  最后,对通信模型设计到的设计到的数据类进行介绍:

 

  AMS 服务端用到的数据类:

    ProcessRecord.java  路径:  \frameworks\base\services\java\com\android\server\am\ ProcessRecord.java

        说明: 记录每个进程的里的全部信息 。 主要信息包括该进程中包含的Activity、Provider、Service等信息、进程文件信息、

             该进程的内存状态信息。

        源代码(部分)如下: 


class ProcessRecord implements Watchdog.PssRequestor {  // 第一个应用程序的ApplicationInfo对象  final ApplicationInfo info; // all about the first app in the process  final String processName; // name of the process 进程名  // List of packages running in the process  final HashSet<String> pkgList = new HashSet(); // 该进程里运行的应用程序包名  // contains HistoryRecord objects  final ArrayList activities = new ArrayList(); // 保存该进程下所有Activity的信息<activty  // /> AndroidManifest.xml  // all ServiceRecord running in this process  final HashSet services = new HashSet(); // 保存该进程下所有Service的信息 <Service />  
}  

 HistoryRecord.java   路径:\frameworks\base\services\java\com\android\server\am\HistoryRecord.java

         说明: 记录每个Activity的全部信息,因为AMS不知道客户端Activity的存在,因此在服务端用HistroyRecord对象来方便

     管理和统计对应客户端Activity的信息。而且该类也是一个Binder类,因此可以跨进程调用。在客户端中,ActivityThread同样

     用HistroyRecord的“代理“ Proxy对象去标记对应的Activity。

           源代码(部分)如下:

**  * An entry in the history stack, representing an activity.  */  
class HistoryRecord extends IApplicationToken.Stub {  final ActivityInfo info; // all about me     final Intent intent; // the original intent that generated us   final String shortComponentName; // the short component name of the intent    TaskRecord task;        // the task this is in.  该Activity对应Task的信息  ProcessRecord app;  // if non-null, hosting application 该Activity所在的进程信息  boolean stopped;        // is activity pause finished?  该Activity是否已经停止 即onStop();  boolean delayedResume;  // not yet resumed because of stopped app switches? 是否需要暂时停止启动  boolean finishing;      // activity in pending finish list?  是否正在finish 即杀死该Activity  ...  
}  

   TaskRecord.java       路径:\frameworks\base\services\java\com\android\server\am\TaskRecord.java

         说明: 记录每个任务 Task的信息。 Activity可以运行在不同的Task中。

           源代码(部分)如下:

class TaskRecord {  // id   final int taskId;       // Unique identifier for this task.  final String affinity;  // The affinity name for this task, or null.  final boolean clearOnBackground; // As per the original activity.  //启动一个新的Task的的Intent信息  Intent intent;          // The original intent that started the task.  Intent affinityIntent;  // Intent of affinity-moved activity that started this task.  ComponentName origActivity; // The non-alias activity component of the intent.  ComponentName realActivity; // The actual activity component that started the task.  //运行在该Task的Activity数目  int numActivities;      // Current number of activities in this task.  
}  

 ActivityManagerService.java

        PS:该类还是相当庞大的,有着琳琅满目的数据对象,稍不注意,就给迷失了。

           源代码(部分)如下:

class ActivityManagerService extends ActivityManagerNative implements xxx {  // This is the maximum number of activities that we would like to have  // running at a given time.  static final int MAX_ACTIVITIES = 20;  //系统中正在运行的Activity数目,最大为20  // Maximum number of recent tasks that we can remember.  static final int MAX_RECENT_TASKS = 20; //最大的Task数目为20      /** * The back history of all previous (and possibly still * running) activities.  It contains HistoryRecord objects. */  //当前系统中正在运行的Activity信息,即处于onPause、onStop、onResume状态的Activity信息  final ArrayList mHistory = new ArrayList();    /** * Current activity that is resumed, or null if there is none. */  HistoryRecord mResumedActivity = null;  //当前正在于用户交互的Activity信息,即处于onResume状态。  /** * When we are in the process of pausing an activity, before starting the * next one, this variable holds the activity that is currently being paused. */  HistoryRecord mPausingActivity = null;  //当前正在暂停的Activity信息,即正在onPause();  /** * All of the applications we currently have running organized by name. * The keys are strings of the application package name (as * returned by the package manager), and the keys are ApplicationRecord * objects. */  //当前正在运行的Process信息  final ProcessMap<ProcessRecord> mProcessNames  = new ProcessMap<ProcessRecord>();  //开始启动一个Activity  public final int startActivity(){ ...}  
}  

ActivityThread所在客户端 :

 

   基本对象都已在开篇介绍过,ActivityThread 、ApplicationThread 类。

     ActivityThread .java 

          源代码(部分)如下:

/** * This manages the execution of the main thread in an * application process, scheduling and executing activities, * broadcasts, and other operations on it as the activity * manager requests. * * {@hide} */  
public final class ActivityThread {  //保存了该进程里所有正在运行的Activity信息  , 即没有onDestroy()的Activity  //IBinder对象是HistoryRecord的代理对象,在客户端已IBinder标记每个Activity信息  final HashMap<IBinder, ActivityRecord> mActivities = new HashMap<IBinder, ActivityRecord>();  final H mH = new H();  // H对象 ,Handler子类  Instrumentation mInstrumentation;  ...  
}  

ApplicationThread    是ActivityThread的内部类

        源代码(部分)如下:

public final class ActivityThread {  ...   //Binder类 主用功能是接受从AMS传递过来的消息,做处理后转发给H类去进一步处理。  private final class ApplicationThread extends ApplicationThreadNative{  public final void schedulePauseActivity(){...}  public final void scheduleSendResult{...}  public final void scheduleSendResult(){...}  }  
}  

最后介绍一下ActivityThread的两个内部类。

 

     H类      是ActivityThread的内部类

       说明 :H类是一个Hander子类 ,该类仅仅是为了异步调用而设计的,使用方法同Hander类一样。

           源代码(部分)如下:

public final class ActivityThread {   ...  private final class H extends Handler {  private H() {  SamplingProfiler.getInstance().setEventThread(mLooper.getThread());  }  //处理消息  public void handleMessage(Message msg){  switch (msg.what) {  case LAUNCH_ACTIVITY: {  //启动一个Activity  ActivityRecord r = (ActivityRecord)msg.obj;  r.packageInfo = getPackageInfoNoCheck(  r.activityInfo.applicationInfo);  handleLaunchActivity(r, null);                   }   ...  }  }  }  
}  

 ActivityRecord类同样是ActivityThread的内部类

       说明:在客户端保存当前Activity的相关信息,方便ActivityThread管理维护Activity。这个类在实现和功能上对应于AMS的

          HistoryRecord类。

           源代码(部分)如下:

public final class ActivityThread{  ...  //记录了客户端Activity的信息  private static final class ActivityRecord {  IBinder token;  //该变量对应于AMS服务端HistoryRecord对象  Intent intent;  //启动该Activity对应的intent信息  Bundle state;   //保存一些信息  onCreate(state)  Activity activity;  //对应于Activity类  ActivityInfo activityInfo;  //对应的ActivityInfo对象  ...  }  
}

另外我再对客户端Activity、ActivityRecord、ActivityThread 类包含的IBinder token属性进行一下说明:该token变量

     实际上指向的的ActivityManagerService的HistoryRecord对象,他们是一一对应的。在应用程序内部和AMS都通过该token

     变量来标记我们实际需要的Activity信息。 如下图所示:

 对ActivityManagerService通信模型以及数据类有一定认识后,那么现在你就可以具体去接触每个操作是怎么实现的了。 例

  如 startActivity()、 registerReceiver()等。 后面我也会慢慢讲解到的,有兴趣的可以先看如下两篇吧。讲解的都挺详细的,反正

  我是偷了 不少经。 O(∩_∩)O~

 

                          Android核心分析(22)-----Android应用框架之Activity    ( 基于android 2.2 版本)

                  Android应用程序启动过程源代码分析                                    ( 基于android 2.3 版本)



















本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292544.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iOS开发UI篇—直接使用UITableView Controller

iOS开发UI篇—直接使用UITableView Controller 一、一般过程 1 //2 // YYViewController.h3 // UITableView Controller4 //5 // Created by 孔医己 on 14-6-2.6 // Copyright (c) 2014年 itcast. All rights reserved.7 //8 9 #import <UIKit/UIKit.h> 10 11 inter…

怎么做图片文字二维码一起_怎么做?才能让文字编排更出彩

在之前视觉设计文章中&#xff0c;我把视觉设计大致罗列了四个方向&#xff0c;更多的是希望能够为大家带来一些努力方向&#xff0c;在设计的路上不那么困惑迷茫&#xff0c;视觉设计本身涵盖的范围就比较广&#xff0c;同时也没有什么衡量的标准和具体的特征&#xff0c;只有…

.NET6之MiniAPI(八):日志

说明&#xff1a;本篇简单说一下日志中常用的几个点&#xff0c;关于日志&#xff0c;后面重点会说到三方日志提供程序在MiniAPI中&#xff0c;可以通过方法或构造函数中&#xff0c;获取框架自动注入的日志类型&#xff0c;如下方式&#xff1a;app.MapGet("/test",…

为什么你闻不到自己胳肢窝的味道?

▲ 点击查看生活中&#xff0c;我们常常会选择性地忽略一些事。吃螺蛳粉的人不会觉得屋子臭&#xff0c;而别人身上有一点烟味就可以闻到。公司的厕所&#xff0c;别人用完后&#xff0c;总觉得比自己用完时更臭。夏天胳肢窝出汗的味道&#xff0c;自己从来都闻不到&#xff0c…

Android插件化开发之Hook StartActivity方法

第一步、先爆项目demo照片&#xff0c;代码不多&#xff0c;不要怕 第二步、应该知道Java反射相关知识 如果不知道或者忘记的小伙伴请猛搓这里&#xff0c;Android插件化开发基础之Java反射机制研究 http://blog.csdn.net/u011068702/article/details/49863931第三步、应该知道…

ArcGis融合小多边形到相邻多边形

&#xfeff;&#xfeff;在有的时候&#xff0c;我们的数据中可能会有许多细小的图斑&#xff0c;这些并不是我们想要的&#xff0c;需要将它们合并到周围的图斑中&#xff0c;如果一个一个手动合并&#xff0c;那工作量之大简直不敢想象。现在借助ArcGIS的Eliminate工具可以很…

oracle 48小时内_近了近了,内马尔正大步向巴萨走来,西媒称有望48小时内敲定转会...

“即将完成&#xff01;”8月28日的西班牙《每日体育报》给巴萨球迷送上了好消息&#xff0c;称在巴萨高层与大巴黎高层进行最新一轮谈判后&#xff0c;内马尔已经非常接近巴萨了。按照《每日体育报》的说法&#xff0c;巴萨和大巴黎有望在未来24到48小时内就内马尔的转会达成协…

《随机过程》布朗运动理论中的两个反常问题

全世界只有3.14 % 的人关注了爆炸吧知识1827 年&#xff0c;英国植物学家布朗&#xff08;Brown&#xff09;用显微镜观察悬浮在液体中的花粉微粒时&#xff0c;发现花粉微粒总是在做无规则运动。后来人们发现&#xff0c;这是一种广泛存在于自然界、工程技术和社会经济等领域中…

linux之用2张图片描述vim常见命令

对了&#xff0c;使得光标跳转到最后一行是这个命令 G

读《好好学习:个人知识管理精进指南》

关于学习的文章之前写过两篇&#xff1a;《掌握好的学习方法&#xff0c;让你在职场更有竞争力》《程序员是终身学习的职业&#xff0c;应该怎么学习&#xff1f;》我们都是终身学习者&#xff0c;我深知学习的重要性&#xff0c;所以每隔一段时间&#xff0c;有些新的心得和想…

跨域解决方案大全

什么是跨域 注&#xff1a;本文完整示例地址先来说一个概念就是同源&#xff0c;同源指的是协议&#xff0c;端口&#xff0c;域名全部相同。 同源策略&#xff08;Same origin policy&#xff09;是一种约定&#xff0c;它是浏览器最核心也最基本的安全功能&#xff0c;如果缺…

2013年下半年信息系统项目管理师考试试卷(回忆版)

2013年下半年信息系统项目管理师上午试卷&#xff08;网友回忆版&#xff09;信息系统的生命周期可以分为立项、开发、运维和消亡4个阶段&#xff0c;应在信息系统建设的&#xff08;1&#xff09;考虑系统消亡的条件和时机。&#xff08;1&#xff09;A&#xff0e;初期B&…

酱油和gbt酱油哪个好_酱油可不是越贵越好?看清瓶身上的5个字,教你1分钟买到好酱油...

今天妈妈做饭说酱油用完了&#xff0c;让我去打酱油的地方打5毛钱的酱油&#xff0c;我拿起塑料壶去打酱油&#xff0c;闻起来香香的&#xff0c;一个推自行车的过来&#xff0c;我问他这酱油是勾兑酱油吗&#xff1f;推自行车的小哥&#xff0c;看了我一眼&#xff0c;问我是监…

让 WPF 的 RadioButton 支持再次点击取消选中的功能

让 WPF 的 RadioButton 支持再次点击取消选中的功能目录让 WPF 的 RadioButton 支持再次点击取消选中的功能零、前言一、方法一&#xff1a;后台直接处理二、方法二&#xff1a;提取为自定义控件&#xff08;用户控件&#xff09;三、方法三&#xff1a;附加行为法独立观察员 2…

java数组转换成string_java面试复习重点:类的管理及常用工具,教你抓住面试重点

java复习&#xff1a; 类的管理及常用工具类包写在程序文件的第一行一个Java 源文件中只能声明一个包&#xff0c;且声明语句只能作为源文件的第一条指令导入类能导入非public类&#xff0c;但是不能用因为在其他包缺省的权限用不了package Testp;import Testpackage.*;public …

ubuntu 新建的用户 table 无法补全命令 解决办法

为什么80%的码农都做不了架构师&#xff1f;>>> vi /etc/passwd 用adduser命令新增了用户之后&#xff0c;发现在该新建用户下的命令终端&#xff0c;使用方向键无法调出历史命令&#xff0c;同时tab键也无法补全输入命令。 找到 你新增的用户xxx 修改/bin/bash…

【Unity3D基础】让物体动起来②--UGUI鼠标点击逐帧移动

背景 上一篇通过鼠标移动的代码很简单&#xff0c;所以看的人也不多&#xff0c;但是还是要感谢“武装三藏”在博客园给出的评论和支持&#xff0c;希望他也能看到第二篇&#xff0c;其实可以很简单&#xff0c;而且是精灵自控制&#xff0c;关键是代码少是我喜欢的方式&#x…

一个有趣的Go项目,3D界面管理k8s集群,真好玩!

大家好&#xff0c;我是小碗汤&#xff0c;今天分享一个用Golang开发&#xff0c;很好玩的工具KubeCraftAdmin[1]&#xff1a;用Minecraft方式管理k8s的工具&#xff0c;感兴趣的兄弟不妨玩一玩。文末有视频&#xff0c;供您鉴赏~Minecraft&#xff1a;我的世界&#xff0c;是微…

java 数组拼接_打印Java数组最优雅的方式是什么?这波操作闪瞎我

在 Java 中&#xff0c;数组虽然是一个对象&#xff0c;但并未明确的定义这样一个类&#xff0c;因此也就没有覆盖 toString() 方法的机会。如果尝试直接打印数组的话&#xff0c;输出的结果并不是我们预期的结果。那有没有一些简单可行的方式呢&#xff1f;如果大家也被这个问…