Binder跨进程通讯机制以及在PMS签名获取中的应用

Binder跨进程通讯

Binder跨进程通讯需要四部分参与工作:Client端Server端ServiceManagerBinder驱动,整体工作流程如下。

  1. Server端创建Binder本地对象,然后通过Binder驱动向ServiceManager进程中注册添加服务。
  2. Client端通过Binder驱动向ServiceManager进程中查询并请求服务,然后Binder驱动会返回一个BinderProxy代理对象。
  3. 数据传递:Client端通过BinderProxy代理对象向binder驱动copy序列化数据,然后binder驱动自动进行BinderProxy和Binder本地对象的转换,将传递的序列化数据map映射到Service端。
  4. 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端PackageManagerServiceBinderProxy代理对象的封装类。

ApplicationPackageManager类中的mPM是通过调用android.app.ActivityThreadgetPackageManager获取的,getPackageManager通过调用ServiceManager.getService("package")ServerManager进程中查询并利用Binder驱动返回一个BinderProxy代理对象。

进一步调用asInterfaceBinderProxy代理对象封装成android.content.pm.IPackageManager.Stub.Proxy对象。

Stubcom.android.server.pm.IPackageManager抽象内部类,继承自android.os.Binder类,实现了com.android.server.pm.IPackageManager接口

ProxyStub的内部类,实现了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中,并设置codeTRANSACTION_getPackageInfo然后调用mRemote成员,也就是BinderPorxy代理对象的transact函数,最终transact函数会将序列化后的数据copy到binder驱动中,binder驱动再将数据映射到PackageManagerServiceServer进程中。

binder驱动将数据映射完后会调用PackageManagerServiceonTransact函数,PackageManagerService类继承IPackageManager.StubonTransact函数也在com.android.server.pm.IPackageManager.Stub中实现。onTransact函数会判断Client端调用BinderProxy代理对象的transact函数时传入的code进行分类处理,如果是TRANSACTION_getPackageInfo说明是调用getPackageInfo。其会将_data中的数据取出来并调用PackageManagerServicegetPackageInfo的函数,将返回值写入reply

最后onTransact调用super.onTransact返回给Binder驱动,驱动唤醒挂起的Client进程(获取签名的APP进程)里面的线程并将结果返回。也就是唤醒Proxy类的getPackageInfo函数调用BinderPorxy代理对象的transact函数位置。

整个PMS的Binder通讯架构如下图所示

PMS中Binder的通讯流程如下图所示

  1. Client最终会通过BinderProxy代理对象的transcat函数向Server发送数据
  2. Server接收到数据后onTranscat函数会被调用,然后针对不同的调用做出响应
  3. 最终Server将响应结果返回给Client,transcat调用处被唤醒继续执行

IPC获取APK签名

根据上面的分析应用程序获取签名其实就是向与PackageManagerService服务端进行IPC通信,所以可以参考com.android.server.pm.IPackageManager.Stub.Proxy类的getPackageInfo函数,获取到BinderProxy代理对象后调用transact函数获取PackageInfo数据。其中获取BinderProxy代理对象可以利用ActivityThread.getPackageManagerServerManager中查询获取的方式获取,也可以通过反射得到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;
}

参考:https://cloud.tencent.com/developer/article/1199439

posted @ 2023-09-27 00:11  怎么可以吃突突  阅读(194)  评论(0编辑  收藏  举报