ActivityManager在操作系统中有关键的数据,本文利用操作系统源代码,逐步理清ActivityManager的框架,并从静态类结构图和动态序列图两个角度分别进行剖析,从而帮助开发者加强对系统框架及进程通信机制的理解。

ActivityManager的作用

參照SDK的说明,可见ActivityManager的功能是与系统中全部执行着的Activity交互提供了接口,基本的接口环绕着执行中的进程信息,任务信息,服务信息等。比方函数getRunningServices()的源代码是:

public List<RunningServiceInfo> getRunningServices(int maxNum)

throws SecurityException {

try {

return (List<RunningServiceInfo>)ActivityManagerNative.getDefault()

.getServices(maxNum, 0);

} catch (RemoteException e) {

// System dead, we will be dead too soon!

return null;

}

}

从中能够看到,ActivityManager的大多数功能都是调用了ActivityManagerNative类接口来完毕的,因此,我们寻迹来看ActivityManagerNative的代码,并以此揭示ActivityManager的总体框架。

ActivityManager的静态类图

通过源吗,能够发现ActivityManagerNative类的继承关系例如以下:

public abstract class ActivityManagerNative extends Binder implements IActivityManager

继承自Binder类,同一时候实现了IActivityManager接口。

相同的,我们继续沿Binder和IActivityManager上溯,整理出例如以下图所看到的的类结构图。

在这张图中,绿色的部分是在SDK中开放给应用程序开发者的接口,蓝色的部分是一个典型的Proxy模式,红色的部分是底层的服务实现,是真正的动作运行者。这里的一个核心思想是Proxy模式,我们接下来对此模式加以介绍。

Proxy模式

Proxy模式,也称代理模式,是经典设计模式中的一种结构型模式,其定义是为其它对象提供一种代理以控制对这个对象的訪问,简单的说就是在訪问和被訪问对象中间加上的一个间接层,以隔离訪问者和被訪问者的实现细节。

结合上面的类结构图,当中ActivityManager是一个client,为了隔离它与ActivityManagerService,有效减少甚至消除二者的耦合度,在这中间使用了ActivityManagerProxy代理类,全部对ActivityManagerService的訪问都转换成对代理类的訪问,这样ActivityManager就与ActivityManagerService解耦了。这就是代理模式的典型应用场景。

为了让代理类与被代理类保持一致的接口,从而实现更加灵活的类结构,或者说完美的屏蔽实现细节,通常的作法是让代理类与被代理类实现一个公共的接口,这样对调用者来说,无法知道被调用的是代理类还是直接是被代理类,由于二者的接口是同样的。

这个思路在上面的类结构图里也有落实,IActivityManager接口类就是起的这个作用。

以上就是代理模式的思路,有时我们也称代理类为本地代理(Local Proxy),被代理类为远端代理(Remote Proxy)。

本地代理与远端代理的Binder

我们再来看一下Binder类的作用,Binder的含义可能译为粘合剂更为贴切,即将两側的东西粘贴起来。在操作系统中,Binder的一大作用就是连接本地代理和远端代理。Binder中最重要的一个函数是:

public final boolean transact(int code, Parcel data, Parcel reply,

int flags) throws RemoteException {

……

boolean r = onTransact(code, data, reply, flags);

if (reply != null) {

reply.setDataPosition(0);

}

return r;

}

它的作用就在于通过code来表示请求的命令标识,通过data和reply进行数据传递,仅仅要远端代理能实现onTransact()函数,就可以做出正确的动作,远端的运行接口被全然屏蔽了。

当然,Binder的实现还是非常复杂的,不仅是类型转换,还要透过Binder驱动进入KERNEL层来完毕进程通信,这些内容不在本文的范围之内,故此处不再深入解析对应的机制。此处我们仅仅要知道Binder的transact()函数实现就能够了。

到此为止,我们对ActivityManager的静态类结构就分析完了,但这还不足以搞清在系统执行中的调用过程,因此,我们下面图的序列图为基础,结合源代码探索一下ActivityManager执行时的机制。

动态序列图

我们以ActivityManager的getRunningServices()函数为例,对上述序列图进行解析。

public List<RunningServiceInfo> getRunningServices(int maxNum)

throws SecurityException {

try {

return (List<RunningServiceInfo>)ActivityManagerNative.getDefault()

.getServices(maxNum, 0);

} catch (RemoteException e) {

// System dead, we will be dead too soon!

return null;

}

}

能够看到,调用被托付到了ActivatyManagerNative.getDefault()。

static public IActivityManager asInterface(IBinder obj)

{

……

return new ActivityManagerProxy(obj);

}

static public IActivityManager getDefault()

{

……

IBinder b = ServiceManager.getService("activity");

gDefault = asInterface(b);

return gDefault;

}

从上述简化后的源代码能够看到,getDefault()函数返回的是一个ActivityManagerProxy对象的引用,也就是说,ActivityManager得到了一个本地代理。

由于在IActivityManager接口中已经定义了getServices()函数,所以我们来看这个本地代理对该函数的实现。

public List getServices(int maxNum, int flags) throws RemoteException {

Parcel data = Parcel.obtain();

Parcel reply = Parcel.obtain();

……

mRemote.transact(GET_SERVICES_TRANSACTION, data, reply, 0);

……

}

从这个代码版段我们看到,调用远端代理的transact()函数,而这个mRemote就是ActivityManagerNative的Binder接口。

接下来我们看一下ActivityManagerNative的代码,由于该类是继承于Binder类的,所以transact的机制此前我们已经展示了代码,对于该类而言,重要的是对onTransact()函数的实现。

public boolean onTransact(int code, Parcel data, Parcel reply, int flags)

throws RemoteException {

switch (code) {

case GET_SERVICES_TRANSACTION: {

……

List list = getServices(maxNum, fl);

……

return true;

}

……

}

return super.onTransact(code, data, reply, flags);

}

在onTrasact()函数内,尽管代码特别多,但就是一个switch语句,依据不同的code命令进行不同的处理,比方对于GET_SERVICES_TRANSACTION命令,仅仅是调用了getServices()函数。而该函数的实现是在ActivityManagerService类中,它是ActivityManagerNative的子类,对于该函数的实现细节,不在本文中具体分析。

Activity启动

在经过前文的学习以后,我们一起来整理一下Activity的启动机制。就从Activity的startActivity()函数開始吧。

startActivity()函数调用了startActivityForResult()函数,该函数有源代码例如以下:

public void startActivityForResult(Intent intent, int requestCode) {

……

Instrumentation.ActivityResult ar =

mInstrumentation.execStartActivity(

this, mMainThread.getApplicationThread(), mToken, this,

intent, requestCode);

……

}

可见,功能被托付给Instrumentation对象来运行了。这个类的功能是辅助Activity的监控和測试,在此我们不具体描写叙述,我们来看它的execStartActivity()函数。

public ActivityResult execStartActivity(

Context who, IBinder contextThread, IBinder token, Activity target,

Intent intent, int requestCode) {

……

try {

int result = ActivityManagerNative.getDefault()

.startActivity(whoThread, intent,

intent.resolveTypeIfNeeded(who.getContentResolver()),

null, 0, token, target != null ? target.mEmbeddedID : null,

requestCode, false, false);

checkStartActivityResult(result, intent);

} catch (RemoteException e) {

}

return null;

}

在这个函数里,我们看到了前文熟悉的ActivityManagerNative.getDefault(),没错,利用了ActivityManagerService。通过前文的线索,利用Proxy模式,我们能够透过ActivityManagerProxy,通过Binder的transact机制,找到真正的动作运行者,即ActivityManagerService类的startActivity()函数,并沿此线索继续追踪源代码,在startActivityLocked()函数里边看到了mWindowManager.setAppStartingWindow的语句调用,mWindowManager是WindowManagerService对象,用于负责界面上的详细窗体调试。

通过这种源代码追踪,我们了解到了Activity启动的底层实现机制,也加深了对Proxy模式和Binder机制的理解。从而为学习其它框架打下了基础。

总结

本文从静态类结构和动态类结构两个角度分析了ActivityManager的框架,兼顾了Binder机制和代理模式在进程间通信的机理,对帮助开发者深化操作系统的结构和框架具有一定的指导作用。

Android源代码学习之六——ActivityManager框架解析的更多相关文章

  1. jQuery源代码学习之六——jQuery数据缓存Data

    一.jQuery数据缓存基本原理 jQuery数据缓存就两个全局Data对象,data_user以及data_priv; 这两个对象分别用于缓存用户自定义数据和内部数据: 以data_user为例,所 ...

  2. Android 核心分析 之六 IPC框架分析 Binder,Service,Service manager

    IPC框架分析 Binder,Service,Service manager 我首先从宏观的角度观察Binder,Service,Service Manager,并阐述各自的概念.从Linux的概念空 ...

  3. android开发学习--网络请求框架RxJava+Retrofit

    看了好多的博客,终于弄清楚了Rxjava和Retrofit,给大家推荐几个不错的文章: https://gank.io/post/56e80c2c677659311bed9841 这个文章是只用Ret ...

  4. Android驱动学习-灯光系统总体框架

    Android的app访问硬件的大致流程可以分为一下几个步骤: 我们之前说过Android系统在添加新的硬件的时候需要添加一个接口java文件,通过jni来访问硬件. 这个java是我们自己实现的,我 ...

  5. 快速接入 Android BLE 开发的基础框架

    代码地址如下:http://www.demodashi.com/demo/12092.html ** Android BLE基础操作框架,基于回调,操作简单.包含扫描.多连接.广播包解析.服务读写及通 ...

  6. 《Android源代码设计模式解析》读书笔记——Android中你应该知道的设计模式

    断断续续的,<Android源代码设计模式解析>也看了一遍.书中提到了非常多的设计模式.可是有部分在开发中见到的几率非常小,所以掌握不了也没有太大影响. 我认为这本书的最大价值有两点,一个 ...

  7. Android Kotlin Jetpack Compose UI框架 完全解析

    前言 Q1的时候公司列了个培训计划,部分人作为讲师要上报培训课题.那时候刚从好几个Android项目里抽离出来,正好看到Jetpack发布了新玩意儿--Compose,我被它的快速实时打包给吸引住了, ...

  8. Android系统源代码学习步骤

    目前,互联网行业正在朝着移动互联网方向强劲地发展,而移动互联网的发展离不开背后的移动平台的支撑.众所周知,如今在移动平台市场上,苹果的iOS.谷歌的Android和微软的Windows Phone系统 ...

  9. Android源代码解析之(六)--&gt;Log日志

    转载请标明出处:一片枫叶的专栏 首先说点题外话,对于想学android framework源代码的同学,事实上能够在github中fork一份,详细地址:platform_frameworks_bas ...

随机推荐

  1. Apache配置虚拟文件夹

    作为一个Android开发人员,一直以为,至少应该有一个server语言,最近慢慢学习php,当然学习Apache使用.本文介绍Win7环境下,怎样配置Apache的虚拟文件夹. 首先,找到我们Apa ...

  2. 全然符合package.json在CommonJS中的规范

    众所周知,package.json是CommonJS规定的用来描写叙述包的文件,全然符合规范的package.json文件应该含有一下字段. name:包的名称,必须是唯一的.由小写英文字母.数字和下 ...

  3. 怎样在Linux下通过ldapsearch查询活动文件夹的内容

    从Win2000開始.微软抛弃NT域而採用活动文件夹来管理Windows域.而活动文件夹就是微软基于遵守LDAP协议的文件夹服务.假设用扫描器扫描的话能够发现活动文件夹的389port是打开的.并且微 ...

  4. 华为C8816电信版ROOT过程

    华为C8816电信版ROOT方法, 网上的方法都不太靠谱.. 昨天弄了好久, 最终搞定.. 整理了一下.. 实用到的就方便多了. <方法不再啰嗦, 都有说明> 1. 获取手机解锁passw ...

  5. 定义Java类的数组的问题

    定义了一个类: class Student{ private int Id; public int getId() { return Id; } public void setId(int id) { ...

  6. WPF动态改变主题颜色

    原文:WPF动态改变主题颜色 国内的WPF技术先行者周银辉曾介绍过如何动态改变应用程序的主题样式,今天我们来介绍一种轻量级的改变界面风格的方式--动态改变主题色. 程序允许用户根据自己的喜好来对界面进 ...

  7. cocos2d-x截图功能clippingnode它也可用于——白费

    许多其他精彩分享:http://blog.csdn.net/u010229677 3.1版本号: 在Director数: bool Director::saveScreenshot(const std ...

  8. leetcode第一刷_Pow(x, n)

    高速乘方的算法,写了好多变,出了各种错,真是服了我自己了. 思想是每次对n减半,将当前的temp平方.须要注意的是假设当前的n是个奇数,减半之后会丢失掉一次乘积,因此假设当前的n为奇数,应该先在结果里 ...

  9. JQuery日记_5.13 Sizzle选择器(六)选择器的效率

        当选择表达式不符合高速匹配(id,tag,class)和原生QSA不可用或返回错误时,将调用select(selector, context, results, seed)方法,此方法迭代DO ...

  10. java实现xml文件CRUD

    java删除xml多个节点: 方案1.你直接改动了nodeList.这一般在做循环时是不同意直接这么做的. 你能够尝试在遍历一个list时,在循环体同一时候删除list里的内容,你会得到一个异常.建议 ...