Android中的Binder学习笔记

简介: Android中的Binder学习笔记

本文内容是我从《Android内核剖析》一书中学习整理。以便以后复习时方便查阅。


一、Binder


1.关于Binder


1.1 Binder是一种架构,这种架构提供了服务器接口、Binder驱动、客户端接口三个模块。

 

1.2 一个Binder服务器实际上就是一个Binder类的对象,该对象一旦创建,内部就启动一个隐藏线程,该线程接下来会接收Binder驱动发送的消息,接收到消息之后,会执行到Binder对象的onTransact()函数,并按照该函数的参数执行不同的服务代码。因此,要实现一个Binder服务,必须重载onTransact()方法。

 

1.3 任意一个服务端Binder对象呗创建时,同时会在Binder驱动中创建一个mRemote对象,该对象的类型也是Binder类。客户端要访问远程服务时,都是通过mRemote对象。

 

1.4 Binder框架


20150127172008813.png


1.5 客户端想要访问远程服务,必须获取远程服务在Binder对象中对应的mRemote引用。然后调用该引用的transact()方法,而在Binder驱动中,mRemote对象也重载了transact()方法。


2.设计Service端


2.1 继承Binder类即可设计Service端,如下代码:


代码2-1-1设计Service示例

public class MusicPlayerService extends Binder{
      @Override
      protected boolean onTransact(intcode,Parceldata,Parcel reply,intflags){
         switch(code){
             case1000:{
                 data.enforceInterface(“MusicPlayerService”);
                 String filePath=data.readString();//从包裹中取出一个字符串
                start(filePath);
                //replay.writeXXX();
               break;
            }
         }
         return super.onTransact(code,data,reply,flags);
      }
      publi cvoid start(String filePath){}
      public void stop(){}
}


2.2 当要启动该服务时,只需初始化一个MusicPlayerService对象即可,如果在Activity里面初始化一个MusicPlayerServeice,然后运行,会在DDMS中发现多了一个线程。


2.3 code变量用于表示客户端期望调用服务端的那个函数,因此双方约定一组int值,不同的值代表不同的服务器函数,该值与客户端的transact()函数中第一个参数code的值是一致的。enforceInterface()是为了某种校验,它与客户端的writeInterfaceToken()对应。


3 Binder客户端设计


3.1transact()函数原型为:


      public final boolean transact(intcode,Parceldata,Parcel reply,intflags);


data表示的是要传递给远程Binder服务的包裹(Parcel),远程服务函数所需要的参数必须放入这个包裹中。包裹中只能放入特定类型的变量如:String、int、long等。除了一般原子变量外,Parcel还提供了writeParcel()方法,因此,要进行Binder远程服务调用时,服务函数的参数要么是一个原子类,要么必须继承Parcel类。参数falsgs含义是执行IPC调用模式,分为两种:一种是双向,用0表示,含义是服务端执行完成后会返回一定的数据;另一种是单向,用1表示,含义是不返回任何数据。


3.2 客户端调用transact()方法:


代码3-3-1客户端调用transact()示例

IBinder mRemote=null;
String filePath=”/sdcard/music/heal_the_world.mp3”;
intcode = 1000;
Parcel data=Parcel.obtain();//包裹不是客户端自己创建的,而是申请到的
data.writeInterfaceToken(“MusicPlayerService”);//标注远程服务名称,不是必需的
data.writeString(filePath);//向包裹中添加String,注意,添加的内容是有序的,约定好的
mRemote.transact(code,data,reply,0);
IBinder binder=reply.readStrongBinder();
reply.recycle();
data.recycle();


3.3 调用transact()方法后,客户端线程进入Binder驱动,Binder驱动会挂起当前线程,并向远程服务发送一个消息,消息中包含客户端传进来的包裹。


4 获取Binder对象


4.1 手工编写Binder服务端和客户端的过程存在两个重要问题


    (1)客户端如何获得服务端的Binder对象引用


    (2)客户端和服务端必须事先约好两件事情:


        (a)服务端函数的参数在包裹中的顺序


        (b)服务端不同函数的int型标识



4.2Android的Service与Binder关系:


    AmS提供了startService()函数用于启动客户服务,而对于客户端来说,可以使用以下两个函数来和一个服务建立连接,其原型在android.app.ContextImpl类中。


    public ComponentName startService(Intent intent);


该函数启动服务后,客户端暂时还没有服务端的Binder引用,因此暂时还不能调用任何服务功能。


    public booleanbindService(Intent service,ServiceConnection conn,int flags);

该函数用于绑定一个服务,这就是第一个重要问题的关键所在。第二个参数是一个interface类,该interface的定义如下代码:


代码4-2-1ServiceConnection接口定义

publicinterface ServiceConnection{
    public void onServiceConnected(ComponentName name,IBinder service);
    public void onServiceDisconnected(ComponentName name);
}



注意该接口中的onServiceConnected()方法的第二个参数service。当客户端请求AmS启动某个Service后,该Service如果正常启动,那么AmS就会远程调用ActivityThread类中的ApplicationThread对象,调用的参数中会包含Service的Binder引用,然后在ApplicationThread中会回调bindService中的conn接口。


因此在客户端中可以在onServiceConnected()方法中将其参数Service保存为一个全局变量,从而在客户端的任何地方都可以随时随地调用该远程服务,这就解决了第一个问题,即客户端如何获取远程服务的Binder引用。流程如下:


20150127172828326.png


图4.2.1Binder客户端和服务端的调用过程


4.3 保证包裹内参数顺序aidl工具的使用


    关于第二个问题,Android的SDK中提供了一个aidl工具,该工具可以吧一个aidl文件转换为一个Java类文件,在该Java类文件,同时重载了transact和onTransact()方法,统一了存入包裹盒读取包裹参数,从而使设计者可以吧注意力放到服务代码本身上。


5.系统服务中的Binder对象


5.1ServiceManager是一个独立进程,其作用是管理各种系统服务,管理的逻辑如图所示:


20150127172950304.png


5.2ServiceManager本身也是一个Service,Framework提供了一个系统函数,可以获取该Service对应的Binder引用,那就是BinderInternal.getContextObject()。


该静态函数返回ServiceManager后,就可以通过ServiceManager提供的方法获取其他系统Service的Binder的引用。其他系统服务在启动时,首先把自己的Binder对象传递给ServiceManager,即所谓的注册(addService)。

 



相关文章
|
2月前
|
存储 Linux Android开发
Android底层:通熟易懂分析binder:1.binder准备工作
本文详细介绍了Android Binder机制的准备工作,包括打开Binder驱动、内存映射(mmap)、启动Binder主线程等内容。通过分析系统调用和进程与驱动层的通信,解释了Binder如何实现进程间通信。文章还探讨了Binder主线程的启动流程及其在进程通信中的作用,最后总结了Binder准备工作的调用时机和重要性。
Android底层:通熟易懂分析binder:1.binder准备工作
|
7月前
|
安全 Java 定位技术
Android 浅度解析:AIDL & Binder (1)
Android 浅度解析:AIDL & Binder (1)
253 0
|
5月前
|
缓存 安全 Java
Android深入Binder拦截问题分析
【7月更文挑战第1天】Android Binder 拦截可实现虚拟化、测试、SDK检测、逆向分析及ROM扩展。通过Java层aidl代理,利用IBinder接口规范来拦截通信。拦截步骤包括:替换Binder服务缓存对象,如ActivityManagerService;代理ServiceManager以控制服务获取。此操作需系统权限,可能涉及安全风险和版本差异,非必要时应谨慎。
|
7月前
|
架构师 网络协议 算法
Android高级架构师整理面试经历发现?(大厂面经+学习笔记(1)
Android高级架构师整理面试经历发现?(大厂面经+学习笔记(1)
|
7月前
|
消息中间件 缓存 架构师
2024年阿里Android高级面试题分享,附学习笔记+面试整理+进阶书籍
2024年阿里Android高级面试题分享,附学习笔记+面试整理+进阶书籍
|
Java API Android开发
Android中Binder在项目中的具体使用详解
Android中Binder在项目中的具体使用详解
208 0
|
缓存 安全 数据库
Android学习笔记4
Android学习笔记4
62 0
|
XML 数据库 数据安全/隐私保护
Android学习笔记3
Android学习笔记3
165 0
|
XML Java Android开发
Android学习笔记2
Android学习笔记2
77 0
|
XML Java Linux
Android学习笔记1
Android学习笔记1
60 0