IPC是Inter-Process Communication的缩写,含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。
Android在什么时候会有跨进程通信的需要?Android在请求系统服务的时候会有跨进程通信的需求,例如访问手机通讯录、获取定位等等行为,本文的目标即是实现一个简易的捕捉这些行为的沙箱
Binder是Android中的一种跨进程通信方式,可以理解为是IPC的一种具体实现方式
ServiceManager
是Android中一个及其重要的系统服务,从它的名称上就可以知道,它是用于管理系统服务的
ServiceManager
由init
进程启动
ServiceManager
负责了以下的一些功能:服务的注册与查找、进程间通信、系统服务的启动与唤醒、提供系统服务的清单实例
binder
驱动决定了底层的通信详情,那么ServiceManager
则相当于导航,告诉具体的通信该怎么走,达到那里等
以WifiManager
类的getConnectInfo
函数(该函数获取wifi信息)为例进行分析
ctrl+左键
查看引用,可以发现该函数定义在android.net.wifi.WifiManager
类中,如下图所示:
从上图可以看到,getConnectInfo
函数具体代码只有一句throw new RuntimeException("Stub!");
,这告诉我们这个函数是由rom中相同的类去替代执行,该函数在这被定义是编译所需要(PS:可以参考https://blog.csdn.net/ttkatrina/article/details/76180641 ),在android源码中的目录frameworks/base/wifi/java/amdroid/net/wifi
下我们可以找到该类,然后找到该函数的具体实现,如下图所示:
可以发现该函数调用了IWifiManager
的getConnectionInfo
函数,在frameworks/base/wifi/java/amdroid/net/wifi
目录下可以找到IWifiManager.aidl
文件,该aidl中定义了getConnectionInfo
函数,如下图所示:
这里需要引入一个概念 --- AIDL
,AIDL
是android的一种接口语言,用于公开android服务的接口,以此来实现跨进程的函数调用。AIDL
在编译时会生成两个类,即Stub
和Proxy
两个类,Stub
类是服务端抽象层的体现,Proxy
是客户端获取的实例,android通过proxy-stub
这种设计模式实现了IPC
下面写一个aidl文件然后生成相应的java代码来看看是怎么实现调用的,首先,我们在android studio中随便找一个项目,然后新建一个aidl文件,如下图所示:
然后Build->Make Probject
即可生成,生成的路径位于build/generated/aidl_source_output_dir/debug/out/包名
,如下图所示:
观察生成后的java文件可发现,Proxy
类已经生成,在Proxy
类中我们可以找到我们定义的函数,如下图所示:
具体分析一下该函数,首先通过obtain
函数生成了一个Parcel
实例,然后调用Parcel
的write
系列函数进行写入,其实就是一个序列化的过程,然后调用了IBinder
的transact
函数,跟踪分析一下该函数,在目录frameworks/base/core/java/android/os
下可以找到该java文件,如下图所示:
可以发现,IBinder
仅仅是一个接口,其中定义了transact
方法,该方法有4个参数,第一个参数code
在我们的远程调用中为函数编号,服务端接受到这个编号后,会去寻找Stub
类中的静态变量,从而解析出是调用那个函数,第二个和第三个参数_data
、_reply
为传入的参数和返回的值,都是经过序列化后的数据,最后一个参数flags
为指示是否需要阻塞等待结果,0为阻塞等待,1为立即返回。
全局搜索一下,可以发现同目录下的BinderProxy
类实现了该接口(PS:值得注意的是,同目录下面还存在一个Binder
类,也实现了该接口,但Binder
类是服务端的实现,而不是客户端的实现),如下图所示:
分析该函数,可以发现最后走向了transactNative
函数,到此为止,进行IPC通信客户端java层已经分析完毕
全局搜索一下transactNative
函数,可以发现该函数在native层中注册信息,如下图所示:
跟踪一下android_os_BinderProxy_transact
函数,可以发现该函数首先通过getBPNativeData(env, obj)->mObject.get()
获取到了一个BpBinder
对象,然后调用了BpBinder
的transact
函数,如下图所示:
[注意]看雪招聘,专注安全领域的专业人才平台!