106°

[日更-2019.5.28] Android系统中的Binder通信机制分析(三)--服务调用的模式

声明

  • 其实对于Android系统Binder通信的机制早就有分析的想法,记得去年6、7月份Mr.Deng离职期间约定一起对其进行研究的,但因为我个人问题没能实施这个计划,留下些许遗憾...
  • 最近,刚好在做公司某项目中一个难题就是关于Binder的,于是想借此机会对其进行尽量深入的分析,以算是弥补过去的遗憾吧。而且,一年后我对于Android系统的理解,比去年确实加深了很多;
  • 文中参考了很多前辈们写的书籍及博客内容,可能涉及的比较多先不具体列出来了,等有时间再添加进来;
  • 本文使用的代码是LineageOS的cm-14.1,对应Android 7.1.2,可以参考我的另一篇博客:如何下载Nexus5的LineageOS14.1(cm-14.1)系统源码并编译、刷机

1 Android系统服务的调用模式

    Android的框架中的各个服务都是实现在system_server线程中的。应用在调用它们时,必须使用进程间通信的方式。因此Binder就要发挥作用了。应用程序需要先在自己的进程中调用Binder,获取一个端点描述符,随后才能与远程服务建立连接。

实现模块 作用范围 索引目录 预处理器 通信信道
Binder 本地 servicemanager aidl /dev/binder

    对于Android应用的开发者来说,他根本不用知道服务调用的底层实现方式。他们只要知道调用Context对象的getSystemService()方法,这个方法只需接收某个Android系统服务的服务名作为输入参数,就能返回一个具体格式/含义不详的对象,通过这个对象就能得到指定的服务对象,井通过它调用服务的方法。突然觉得Android的分层做的确实太好了! Android系统服务的调用模式如下图所示(从网上盗图):

           

    这一架构的一个明显的缺点:过程间通信的开销实在是太大了,特别是在必须进行的序列化和解序列化消息的过程中,以及在交替切换进程时所必需进行的进程上下文切换时,开销尤为巨大。(这段话还有待理解,我目前还没理解它的意思

    我觉得Android系统在设计IPC机制的时候除了想方便APP开发者使用,还想做到权限隔离及安全性。正常逻辑来说,系统对自己人(系统服务)和外人(APP)的态度是完全不同的,系统默认会把安装上来的APP当贼防着,只会给它一个最小权限,APP想要完成任何操作,都必须完全依赖于服务调用。而系统对系统服务进程则是信任的,Android系统指望通过系统服务进行所有的安全检查,在同意对相关请求提供服务之前,确认对应的客户端确实拥有权限。而Android APP所需要的权限写在apk安装包中的manifest文件中,权限的声明都是位于应用运行时的作用域之外的,而应用自身是无法修改它们的。

2 序列化和Android接口定义语言(AIDL)

    通过getSystemService()方法返回的对象只是一个系统服务的“代理”(Proxy),在这个对象内部记录着一个通过调用binder获得的指向实际服务的引用,而该对象导出的各个方法,在大多数情况下实际上也只是一些stub容器(Parcel),其中存放的是被顺序打包(序列化)到Binder消息里去的,需要传递给远程方法的各个参数。远程调用的各种方法及其参数就是以这一方式使用AIDL序列化的。AIDL是一种能被aidl SDK程序(编译过程中,如遇到.aid文件时就会调用它)读懂的Java衍生语言.aidl能够自动生成把相关参数序列化打包到Binder消息中去,并从返回的Binder消息中提取出远程方法的返回值所需的Java源码。这些代码被称为“样板文件”,即它可以根据定义文件自动生成,并保证编译得干净利落。

    从系统源码里举个AIDL文件例子吧,打开源码目录:~/LineageOS/frameworks/base/media/java/android/media/IMediaRouterService.aidl

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import android.media.IMediaRouterClient; import android.media.MediaRouterClientState;

/**

  • {@hide} */ interface IMediaRouterService { void registerClientAsUser(IMediaRouterClient client, String packageName, int userId); void unregisterClient(IMediaRouterClient client);

    MediaRouterClientState getState(IMediaRouterClient client);

    void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan); void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit); void requestSetVolume(IMediaRouterClient client, String routeId, int volume); void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction); }

    这个.aidl文件有点类似于头文件,其中只定义了方法(即可能存在的对象),但并没有给出它们的具体实现代码。aid工具向开发者隐藏了Android IPC机制实现的细节,大多数开发者可以忽略掉Binder所扮演的角色,甚至可以完全无视它的存在。

本文由【Captain_小馬佩德罗】发布于开源中国,原文链接:https://my.oschina.net/XiaoMaPedro/blog/3065499

全部评论: 0

    我有话说: