Binder跨进程通讯机制以及在PMS签名获取中的应用
Binder跨进程通讯
Binder跨进程通讯需要四部分参与工作:Client端
,Server端
,ServiceManager
和Binder驱动
,整体工作流程如下。
- Server端创建Binder本地对象,然后通过Binder驱动向ServiceManager进程中注册添加服务。
- Client端通过Binder驱动向ServiceManager进程中查询并请求服务,然后Binder驱动会返回一个BinderProxy代理对象。
- 数据传递:Client端通过BinderProxy代理对象向binder驱动copy序列化数据,然后binder驱动自动进行BinderProxy和Binder本地对象的转换,将传递的序列化数据map映射到Service端。
- RPC远程过程调用:Client端通过BinderProxy代理对象向binder驱动copy序列化数据(传递需要调用函数的flag和参数),然后binder驱动自动进行BinderProxy和Binder本地对象的转换,将传递的序列化数据map映射到Service端并调用对应的函数。
PMS签名获取过程中的Binder通讯过程
systeam_server
进程中的PackageManagerService
就是Binder通讯中的Server
端,而获取签名信息的APP进程就是Binder通讯中的Client
端。
PackageManagerService
在初始化的时候会调用ServiceManager.addService("package", m)
向ServiceManager
进程中添加一个服务,服务对应的Binder
本地对象就是PackageManagerService
APP进程中一般通过getApplicationContext().getPackageManager().getPackageInfo(packagename, PackageManager.GET_SIGNATURES)
,实际是通过Context
类对象获取到ApplicationPackageManager(继承PackageManager)
类对象,而ApplicationPackageManager
类中的mPM
成员是一个IPackageManager.Stub.Proxy
类对象,是Server端PackageManagerService
的BinderProxy
代理对象的封装类。
ApplicationPackageManager
类中的mPM
是通过调用android.app.ActivityThread
的getPackageManager
获取的,getPackageManager
通过调用ServiceManager.getService("package")
从ServerManager
进程中查询并利用Binder驱动
返回一个BinderProxy
代理对象。
进一步调用asInterface
将BinderProxy
代理对象封装成android.content.pm.IPackageManager.Stub.Proxy
对象。
Stub
是com.android.server.pm.IPackageManager
抽象内部类,继承自android.os.Binder
类,实现了com.android.server.pm.IPackageManager
接口
Proxy
是Stub
的内部类,实现了com.android.server.pm.IPackageManager
接口。其包含了private android.os.IBinder mRemote
, 即Binder驱动
返回的BinderProxy
代理对象。
当APP进程调用getApplicationContext().getPackageManager().getPackageInfo(packagename, PackageManager.GET_SIGNATURES)
的时候,ApplicationPackageManager.getPackageInfo()
的内部实际是直接调用mPM
成员的getPackageInfo
函数,而mPM
成员的类型是com.android.server.pm.IPackageManager.Stub.Proxy
,所以调用的就是Proxy
类的getPackageInfo
函数。此函数会将数据进行序列化为Parcel
类型后保存在_data
中,并设置code
为TRANSACTION_getPackageInfo
然后调用mRemote
成员,也就是BinderPorxy
代理对象的transact
函数,最终transact
函数会将序列化后的数据copy到binder驱动中,binder驱动再将数据映射到PackageManagerService
即Server
进程中。
binder驱动
将数据映射完后会调用PackageManagerService
的onTransact
函数,PackageManagerService
类继承IPackageManager.Stub
,onTransact
函数也在com.android.server.pm.IPackageManager.Stub
中实现。onTransact
函数会判断Client端调用BinderProxy
代理对象的transact
函数时传入的code
进行分类处理,如果是TRANSACTION_getPackageInfo
说明是调用getPackageInfo
。其会将_data
中的数据取出来并调用PackageManagerService
的getPackageInfo
的函数,将返回值写入reply
中
最后onTransact
调用super.onTransact
返回给Binder驱动
,驱动唤醒挂起的Client
进程(获取签名的APP进程)里面的线程并将结果返回。也就是唤醒Proxy
类的getPackageInfo
函数调用BinderPorxy
代理对象的transact
函数位置。
整个PMS的Binder通讯架构如下图所示
PMS中Binder的通讯流程如下图所示
- Client最终会通过
BinderProxy
代理对象的transcat
函数向Server发送数据 - Server接收到数据后
onTranscat
函数会被调用,然后针对不同的调用做出响应 - 最终Server将响应结果返回给Client,
transcat
调用处被唤醒继续执行
IPC获取APK签名
根据上面的分析应用程序获取签名其实就是向与PackageManagerService
服务端进行IPC通信,所以可以参考com.android.server.pm.IPackageManager.Stub.Proxy
类的getPackageInfo
函数,获取到BinderProxy
代理对象后调用transact
函数获取PackageInfo
数据。其中获取BinderProxy
代理对象可以利用ActivityThread.getPackageManager
从ServerManager
中查询获取的方式获取,也可以通过反射得到android.content.pm.IPackageManager$Stub$Proxy
类中的mRemote成员(BinderProxy代理对象),但是这种需要突破SDK API限制。
public PackageInfo my_getPackageInfo(){
PackageInfo packageInfo = null;
try {
//通过反射获取android.content.pm.IPackageManager$Stub$Proxy类中的mRemote成员(BinderProxy代理对象),需要突破SDK API限制
/*
PackageManager packageManager = getBaseContext().getPackageManager();
Class ApplicationPackageManagerClass = getClassLoader().loadClass("android.app.ApplicationPackageManager");
Field mPMField = ApplicationPackageManagerClass.getDeclaredField("mPM");
mPMField.setAccessible(true);
Object mPM_object = mPMField.get(packageManager);
Class ProxyClass = getClassLoader().loadClass("android.content.pm.IPackageManager$Stub$Proxy");
@SuppressLint("SoonBlockedPrivateApi") Field mRemoteField = ProxyClass.getDeclaredField("mRemote");
mRemoteField.setAccessible(true);
IBinder mRemote = (IBinder) mRemoteField.get(mPM_object);
*/
//获取BinderProxy代理对象mRemote
Class ServiceManagerClass = this.getClassLoader().loadClass("android.os.ServiceManager");
//public static IBinder getService(String name)
Method getServiceMethod = ServiceManagerClass.getDeclaredMethod("getService", String.class);
//ServiceManager.getService("package");
IBinder mRemote = (IBinder) getServiceMethod.invoke(null, "package");
//序列化数据,写入_data
Parcel _data = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
_data = Parcel.obtain(mRemote);
}
else{
_data = Parcel.obtain();
}
Parcel _reply = Parcel.obtain();
_data.writeInterfaceToken("android.content.pm.IPackageManager");
_data.writeString(getPackageName());
_data.writeLong(PackageManager.GET_SIGNATURES);
_data.writeInt(android.os.Process.myUid());
//调用transact发送数据到PackageManagerService(Server端)
mRemote.transact(TRANSACTION_getPackageInfo, _data, _reply, 0);
//读取_reply中返回的数据
_reply.readException();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
packageInfo = _reply.readTypedObject(PackageInfo.CREATOR);
}
_data.recycle();
_reply.recycle();
} catch (Throwable e) {
Log.e("reverccqin", "IPC_TEST_getPackageInfo error "+e);
}
return packageInfo;
}