Framework基础:应用是如何跟系统服务打交道的

Android有许多系统服务,例如ActivityManagerService,PowerManagerService等,这些系统服务都跑在SystemServer进程之中。而普通的应用跑在自己的进程里面。那普通应用要怎样才能使用到系统服务呢?这个就相当于普通应用进程跟SystemServer进程进行通行,不同进程进行通信,就是跨进程的通信啦。Android中特有的跨进程通信的方式是binder通信。下面说下应用与系统ActivityManagerService交互的过程。

应用是如何获取到ActivityManager的呢?###

下图是获取ActivityManager的内部时序图

获取ActivityManager内部时序图.png

应用层调用Context的getSystemService方法获取到ActivityManager

ActivityManager mActivityManager;
mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);  

下面调用到ContextImpl的getSystemService

    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }

进入SystemServiceRegistry.getSystemService(this, name)方法,可以看到首先通过SYSTEM_SERVICE_FETCHERS的get方法返回一个ServiceFetcher,然后通过ServiceFetcher的getService方法返回一个ActivityManager。

   public static Object getSystemService(ContextImpl ctx, String name) {
       ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
       return fetcher != null ? fetcher.getService(ctx) : null;
   }

SYSTEM_SERVICE_FETCHERS是一个HashMap,key是服务名称,内容是ServiceFetcher对象。

    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();

SYSTEM_SERVICE_FETCHERS是保存着所有ServiceFetcher的全局变量,我们看看这个全局变量是怎么填充的。通过静态块中的registerService方法填充。

        registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
                new CachedServiceFetcher<ActivityManager>() {
            @Override
            public ActivityManager createService(ContextImpl ctx) {
                return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
            }});

看看这个registerService函数,可以看到SYSTEM_SERVICE_FETCHERS通过put把系统服务填充到自己里面。

    private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }

ServiceFetcher是一个接口,他的实现是CachedServiceFetcher。

    static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }

就是说一个CachedServiceFetcher是跟一个系统服务相关联的,其通过createService创建关联的系统服务,通过getService获取关联的系统服务。看createService方法,可以看到new了一个ActivityManager对象,所以返回的就是一个ActivityManager对象啦。

        registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
                new CachedServiceFetcher<ActivityManager>() {
            @Override
            public ActivityManager createService(ContextImpl ctx) {
                return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
            }});
系统服务数据结构图.png

那ActivityManager是怎么跟ActivityManagerService通信的呢?###

我们以ActivityManager的一个方法为例子看一下就行了,例如获取最近任务的方法ActivityManager.getRecentTasks

    public List<RecentTaskInfo> getRecentTasks(int maxNum, int flags)
            throws SecurityException {
        try {
            return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
                    flags, UserHandle.myUserId());
        } catch (RemoteException e) {
            // System dead, we will be dead too soon!
            return null;
        }
    }

进入ActivityManagerNative的getDefault()方法,方法返回一个IActivityManager的单例,IActivityManager是一个接口,继承于Interface接口。IActivityManager 的实现是ActivityManagerProxy,所以方法其实是返回一个 ActivityManagerProxy的单例对象。这是一个代理对象,用于跟ActivityManagerService进行binder通信。
套路差不多都这样
1.ServiceManager.getService获取到Ibinder
2.通过asInterface获取到远程服务的本地代理。

    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };
}

    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }

        return new ActivityManagerProxy(obj);
    }

ActivityManagerNative相当于aidl通信中的stub的角色,stub继承于binder,专门用于binder通信。ActivityManagerService会继承于这个stub。
很多地方都可以看到这个stub,这个stub可以看作一个中间者的角色吧。这个中间者里面包含着本地代理的类定义,同时这个中间者被远端服务所继承。

IActivityManager是本地代理和远端服务都要实现的接口,就是说本地代理里面的方法要和远端服务的方法一一对应。

首先ActivityManagerService会发布本地的接口,通过ActivityManagerNative的构造方法发布了,接口用descriptor标示,在IActivityManager定义,String descriptor = "android.app.IActivityManager";

  public ActivityManagerNative() {
      attachInterface(this, descriptor);
  }

然后通过Binder的queryLocalInterface可以找到本地对应的接口,这个接口的引用被代理所持有,所以代理就可以使用这个本地接口跟远端服务通信了。

        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);

代理每次调用方法,都会调用到这个本地接口transact方法,把参数跨进程发送到远端服务,远端服务通过onTransact方法,调用到实际的方法。

上面的说法有些逆向,为了正向理解,我们想想基于binder通信你会怎么写呢?
首先整个架构要有两个要素
1.远端服务
2.本地代理
所以有了两个类,远端服务ActivityManagerService,本地代理ActivityManagerProxy。

远端服务和本地代理肯定要实现同样的方法嘛,所有最好设计一个接口给两者实现。所以设计一个接口IActivityManager。

ActivityManagerService为了能够远程被调用到,必须继承于Binder类。所以这时ActivityManagerService既要继承binder,也要实现IActivityManager。因为有binder发布本地接口等操作,把这些东西写到ActivityManagerService会让文件很难看。所以干脆新建立一个stub类ActivityManagerNative类好了,里面包含一些发布本地接口的操作。顺便在这个stub类定义代理类好了,节省一个文件。

几个类的关系图

类关系.png

参考文章:
http://blog.csdn.net/u012950099/article/details/51987036
android的aidl-手动实现aidl自动生成的Java文件

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

推荐阅读更多精彩内容

  • Android跨进程通信IPC整体内容如下 1、Android跨进程通信IPC之1——Linux基础2、Andro...
    隔壁老李头阅读 11,801评论 11 56
  • 毫不夸张地说,Binder是Android系统中最重要的特性之一;正如其名“粘合剂”所喻,它是系统间各个组件的桥梁...
    weishu阅读 17,808评论 29 246
  • 原文:http://weishu.me/2016/01/12/binder-index-for-newer/ 要点...
    指尖流逝的青春阅读 2,603评论 0 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 简单说Binder Binder算是Android中比较难懂的一部分内容了,但是非常的重要,要想研究Framewo...
    EsonJack阅读 1,538评论 0 4