Android 应用工程师的 Binder 原理剖析(六)Java& Native层面 Binder相互转化

前面的一~五章已经基本将Binder通信的上层逻辑解释清楚了,接下来的重点是分析binder的上层 是如何走到native层的,换一句话说,native层如何被封装成为上层的。也就是Binder的 Java和Native层的相互转化。

当讲到Binder的java&Native层的通信,天生最好研究的就是ServiceManager类了,因为,它是运用最广泛的也是大家最熟悉的使用了Binder通信的场景。

大家不妨先来看这个图:

通过上图,我们不难发现,在Binder通信必然需要有JNI层的支撑,缺乏JNI层,将无法完成java到Native层的调用,因此我们必须研究一下Java framework层与Native层之间的相互调动。

1)Client端通过ServiceManager 拿到Server端服务的Binder 代理,也就是BinderProxy(是Server端Binder的一个代理);

2)这个BinderProxy的访问需要经过JNI层的Android_util_binder类将请求转交给native的BpBinder(p代表代理的意思);

3)BpBinder会通过ioctl将请求转交给Binder驱动设备;

4)在服务端注册了一个监听请求的回调函数,一旦驱动层收到BpBinder 的调用,就会回调BBInder注册的回调函数,于是,就将请求转给了BBinder;

5)BBinder拿到请求后,会进行一些数据的处理,然后通过JNI将请求转交给了java类;

6)java层会通过aidl中的函数将请求发送给Server端的实现者,由Server端通过stub 去调用相关的执行代码,并将结果通过类似的路径返回。

以上只是一个大概的流程,具体的实现流程我们将在后面的分析中更详细的介绍。然而要全面的分析这个流程最好的案例便是ServiceManager。

2. ServcieManager场景

在跨进程通信过程中,比如我们与AMS通信,首先需要拿到AMS的binder,然而,AMS的binder往往是通过ServcieManager获取的,因此会有代码:

scss 复制代码
ServiceManager.getService(Context.ACTIVITY_SERVICE)

以上代码将调用下面的代码

kotlin 复制代码
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}

关键函数:Binder.allowBlocking(rawGetService(name))

typescript 复制代码
public static IBinder allowBlocking(IBinder binder) {
try {
if (binder instanceof BinderProxy) {
((BinderProxy) binder).mWarnOnBlocking = false;
} else if (binder != null && binder.getInterfaceDescriptor() != null
&& binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
Log.w(TAG, "Unable to allow blocking on interface " + binder);
}
} catch (RemoteException ignored) {
}
return binder;
}

关键函数中 Binder.allowBlocking并没有什么实质性的有价值的代码,所以所有的核心代码在rawGetService中。

java 复制代码
private static IBinder rawGetService(String name) throws RemoteException {
   --------------- 省略
final IBinder binder = getIServiceManager().getService(name);

   --------------- 省略
return binder;
}

这里的逻辑是,先通过getIServiceManager()获取到IServiceManager对象,然后再通过这个IServiceManager对象获取到一个IBinder。

注意,此处有两个IPC

  1. 获取到IServiceManager
  2. 通过IServiceManager获取到该name的Service的Binder的IPC

由于本文本文重在探索java到native的逻辑,我们且只看第一个。

关于第二个:源码中实现IServiceManager的类是ServiceManagerNative有兴趣的读者可以自己探索下,或者关注笔者后面的文章

ServiceManager.getIServiceManager()

csharp 复制代码
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}

到这,可以看到返回的其实是ServiceManagerNative.asInterface()的返回值。

对AIDL有所了解就知道,asInterface()的内容大概如下:

这个方法属于aidl接口的内部类 Stub。在同一进程中,就会直接返回Stub,如果在另一个进程中调用,就会返回将这个ibinder封装好的Proxy对象。对于上面的逻辑不太清楚的可以先学习前面的章节AIDL。于是,虽然没有看ServiceManagerNative的源码,但是其逻辑已经很清晰了。我们只需要关注IBinder的来源就可以了,也就是BinderInternal.getContextObject()。

BinderInternal.getContextObject()代码如下:

java 复制代码
public static final native IBinder getContextObject();

至此,可以发现IBinder对象其实是从native层获取到的。

JNI层代码如下:

scss 复制代码
android_util_Binder.android_os_BinderInternal_getContextObject()代码如下

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
   sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
   return javaObjectForIBinder(env, b);
}

这里先通过ProcessState获取到了一个native 层的IBinder强引用,也就是一个BpBinder。然后将这个native层的IBinder强引用传入javaObjectForIBinder()方法,最终封装成java层的IBinder然后返回。此处先不深究ProcessState的逻辑,整个native层的binder有自己的一整套的逻辑,后面的文章会继续探索。我们可以先稍微看下javaObjectForIBinder()的大概逻辑。android_util_Binder.javaObjectForIBinder()

kotlin 复制代码
// If the argument is a JavaBBinder, return the Java object that was used to create it.
// Otherwise return a BinderProxy for the IBinder. If a previous call was passed the
// same IBinder, and the original BinderProxy is still alive, return the sameBinderProxy.
// 将一个BpBinder对象(这是native中的类型)转换成java中的类型
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
   // N.B. This function is called from a @FastNative JNI method, so don't take locks
   //around calls to Java code or block the calling thread for a long time for any
   //reason.

   if (val == NULL) return NULL;

//JavaBBinder返回true,其他类均返回flase
   if (val->checkSubclass(&gBinderOffsets)) {
       // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
       jobject object = static_cast<JavaBBinder*>(val.get())->object();
       LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
       return object;
  }

   BinderProxyNativeData* nativeData = new BinderProxyNativeData();
   nativeData->mOrgue = new DeathRecipientList;
   nativeData->mObject = val;

   // 核心代码:运用反射创建一个BinderProxy对象
   jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
           gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
   if (env->ExceptionCheck()) {
       // In the exception case, getInstance still took ownership of nativeData.
       return NULL;
  }
   BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
//如果object是刚刚新建出来的BinderProxy
   if (actualNativeData == nativeData) {
 //处理proxy计数
       // Created a new Proxy
       uint32_t numProxies = gNumProxies.fetch_add(1, std::memory_order_relaxed);
       uint32_t numLastWarned = gProxiesWarned.load(std::memory_order_relaxed);
       if (numProxies >= numLastWarned + PROXY_WARN_INTERVAL) {
           // Multiple threads can get here, make sure only one of them gets to
           // update the warn counter.
           if (gProxiesWarned.compare_exchange_strong(numLastWarned,
                       numLastWarned + PROXY_WARN_INTERVAL, std::memory_order_relaxed))
          {
               ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies);
          }
      }
  } else {
       delete nativeData;
  }

   return object;  //object 是反射参数的java的 BinderProxy
}

上面的函数看起来复杂,其实功能就是将一个BpBinder对象(这是native中的类型)转换成java中的类型,中间采用了反射技术而已。

核心代码进行说明:

ini 复制代码
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
          gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());

gBinderProxyOffsets是什么?

ini 复制代码
static struct binderproxy_offsets_t
{
   // Class state.
   jclass mClass;
   jmethodID mGetInstance;
   jmethodID mSendDeathNotice;

   // Object state.
   //指向BinderProxyNativeData的指针
   jfieldID mNativeData;  // Field holds native pointer to BinderProxyNativeData.
} gBinderProxyOffsets;

const char* const kBinderProxyPathName = "android/os/BinderProxy";

static int int_register_android_os_BinderProxy(JNIEnv* env)
{
  ...
   jclass clazz = FindClassOrDie(env, kBinderProxyPathName);
   gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
   gBinderProxyOffsets.mGetInstance = GetStaticMethodIDOrDie(env, clazz, "getInstance",
           "(JJ)Landroid/os/BinderProxy;");
   gBinderProxyOffsets.mSendDeathNotice =
           GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
                                  "(Landroid/os/IBinder$DeathRecipient;Landroid/os/IBinder;)V");
   gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
  ...
}

可以看到,gBinderProxyOffsets实际上是一个用来记录一些java中对应类、方法以及字段的结构体,用于从native层调用java层代码,而通过int_register_android_os_BinderProxy,我们知道,binderproxy_offsets_t中的mClass字段就是 BInderProxy,而mGetInstance 就是BInderProxy.java 中getInstance方法。因此核心代码创建的是一个BinderProxy对象。

具体的执行流程如下图所示:

第一大步:为了获取ServcieManager 的IServiceManager,首先要ServcieManager进程创建一个底层的Binder,所以会有android_os_BinderInternal_getContextObject也就是第2步,第2步会在ProcessState::self()中初始化Binder驱动,然后再执行第3步;

第二大步:上图中第3步会调用到第4步,在第4步getStrongProxyForHandle代码如下:

scss 复制代码
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
   sp<IBinder> result;

   AutoMutex _l(mLock);

//查找或建立handle对应的handle_entry
   handle_entry* e = lookupHandleLocked(handle);

   if (e != nullptr) {
       // We need to create a new BpBinder if there isn't currently one, OR we
       // are unable to acquire a weak reference on this current one. The
       // attemptIncWeak() is safe because we know the BpBinder destructor will always
       // call expungeHandle(), which acquires the same lock we are holding now.
       // We need to do this because there is a race condition between someone
       // releasing a reference on this BpBinder, and a new reference on its handle
       // arriving from the driver.
       IBinder* b = e->binder;
       if (b == nullptr || !e->refs->attemptIncWeak(this)) {
           if (handle == 0) {
               // Special case for context manager...
               // The context manager is the only object for which we create
               // a BpBinder proxy without already holding a reference.
               // Perform a dummy transaction to ensure the context manager
               // is registered before we create the first local reference
               // to it (which will occur when creating the BpBinder).
               // If a local reference is created for the BpBinder when the
               // context manager is not present, the driver will fail to
               // provide a reference to the context manager, but the
               // driver API does not return status.
               //
               // Note that this is not race-free if the context manager
               // dies while this code runs.
               //
               // TODO: add a driver API to wait for context manager, or
               // stop special casing handle 0 for context manager and add
               // a driver API to get a handle to the context manager with
               // proper reference counting.
//当handle为ServiceManager的特殊情况
//需要确保在创建Binder引用之前,context manager已经被binder注册
//需要先确保邋ServcieManager活着
               Parcel data;
               status_t status = IPCThreadState::self()->transact(
                       0, IBinder::PING_TRANSACTION, data, nullptr, 0);
               if (status == DEAD_OBJECT)
                  return nullptr;
          }

//创建BpBinder并保存下来以便后面再次查找
           b = BpBinder::create(handle);
           e->binder = b;
           if (b) e->refs = b->getWeakRefs();
           result = b;
      } else {
           // This little bit of nastyness is to allow us to add a primary
           // reference to the remote proxy when this team doesn't have one
           // but another team is sending the handle to us.
           result.force_set(b);
           e->refs->decWeak(this);
      }
  }
   return result;
}

其中会执行一个BpBinder::create(handle),此处会创建一个BpBinder对象,并且将BpBinder对象赋值给result对象并返回result,也就是返回BpBinder对象。这个BpBinder对象一路返回,最终在android_util_Binder.cpp中的android_os_BinderInternal_getContextObject函数中会执行下面的代码:

scss 复制代码
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
   sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
   return javaObjectForIBinder(env, b);
}

也就是说b的值是BpBinder,然后BpBinder赋值给了javaObjectForIBinder作为参数。

第三大步:BpBinder需要返回给java层Client端使用,所以此时的封装就是将BpBinder封装成为Java层的BinderProxy对象。因此在Client端得到的IServiceManager 其实是BinderProxy类的子类的对象。

所以,BinderInternal.getContextObject(),返回的是一个层层封装的类的实例,具体来说,是Native层的BpBinder对象被封装成为BinderProxy对象并返回。

3. 出现了几个陌生的概念:BinderProxy,BpBinder,BBinder,IBinder

下面我们一一的介绍这些概念。

3.1 IBinder

arduino 复制代码
// IBinder从Refbase继承而来,一提供强弱指针计数能力
class IBinder : public virtual RefBase
{
public:
  enum {
      FIRST_CALL_TRANSACTION = 0x00000001,
      LAST_CALL_TRANSACTION   = 0x00ffffff,

      PING_TRANSACTION       = B_PACK_CHARS('_','P','N','G'),
      DUMP_TRANSACTION       = B_PACK_CHARS('_','D','M','P'),
      INTERFACE_TRANSACTION   = B_PACK_CHARS('_', 'N', 'T', 'F'),
      SYSPROPS_TRANSACTION   = B_PACK_CHARS('_', 'S', 'P', 'R'),

      // Corresponds to TF_ONE_WAY -- an asynchronous call.
      FLAG_ONEWAY             = 0x00000001
  };

                        IBinder();

  // 根据descriptor查询相应的IInterface对象
  virtual sp<IInterface> queryLocalInterface(const String16& descriptor);

  // 获取descriptor描述符
  virtual const String16& getInterfaceDescriptor() const = 0;

  virtual bool           isBinderAlive() const = 0;
  virtual status_t       pingBinder() = 0;
  virtual status_t       dump(int fd, const Vector<String16>& args) = 0;

  // transact binder通信函数
  virtual status_t       transact(   uint32_t code,
                                      const Parcel& data,
                                      Parcel* reply,
                                      uint32_t flags = 0) = 0;

  // 死亡通知相应类
  class DeathRecipient : public virtual RefBase
  {
  public:
      virtual void binderDied(const wp<IBinder>& who) = 0;
  };

   
  // 如其名,用于注册Binder用的
virtual status_t       linkToDeath(const sp<DeathRecipient>& recipient,
                                      void* cookie = NULL,
                                      uint32_t flags = 0) = 0;

  // 撤销用之前注册的死亡通知函数
virtual status_t       unlinkToDeath( const wp<DeathRecipient>& recipient,
                                          void* cookie = NULL,
                                          uint32_t flags = 0,
                                          wp<DeathRecipient>* outRecipient = NULL) = 0;

  virtual bool           checkSubclass(const void* subclassID) const;

  typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);

  virtual void           attachObject(   const void* objectID,
                                          void* object,
                                          void* cleanupCookie,
                                          object_cleanup_func func) = 0;
  virtual void*           findObject(const void* objectID) const = 0;
  virtual void           detachObject(const void* objectID) = 0;

  // 返回服务端的binder引用
virtual BBinder*       localBinder();
  // 放回客户端的binder引用
virtual BpBinder*       remoteBinder();

protected:
  virtual         ~IBinder();

private:
};

BpBinder的构造函数

scss 复制代码
BpBinder::BpBinder(int32_t handle)
  : mHandle(handle)  // 将传入的handle值保存到mHandle成员变量里
  , mAlive(1)        // mAlive设置为1
  , mObitsSent(0)
  , mObituaries(NULL)
{
   ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);

   extendObjectLifetime(OBJECT_LIFETIME_WEAK);
   IPCThreadState::self()->incWeakHandle(handle);
}
首先调用extendObjectLifetime将对象改为弱引用控制,通过IPCThreadState的incWeakHandle增加Binder Service的如引用计数值。IncWeakHandle如下:

void IPCThreadState::incWeakHandle(int32_t handle)
{
   LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
   mOut.writeInt32(BC_INCREFS);
   mOut.writeInt32(handle);
}

这一步只是将BC_INCREFS请求写到mOut中,还没有发送出去。

除了incWeakHandle函数外还有decWeakHandle,incStrongHandle和decStrongHandle与Binder协议中的其他命令对应起来。这些细节我们就先不分析了。

另外,transact函数是核心,因为,Client是需要通过transact将请求传递给Binder驱动的,所以transact是BpBinder的核心函数之一。

3.3 BBinder

arduino 复制代码
class BBinder : public IBinder
{
public:
                      BBinder();

  virtual const String16& getInterfaceDescriptor() const;
  virtual bool       isBinderAlive() const;
  virtual status_t   pingBinder();
  virtual status_t   dump(int fd, const Vector<String16>& args);

  virtual status_t   transact(   uint32_t code,
                                  const Parcel& data,
                                  Parcel* reply,
                                  uint32_t flags = 0);

  virtual status_t   linkToDeath(const sp<DeathRecipient>& recipient,
                                  void* cookie = NULL,
                                  uint32_t flags = 0);

  virtual status_t   unlinkToDeath( const wp<DeathRecipient>& recipient,
                                      void* cookie = NULL,
                                      uint32_t flags = 0,
                                      wp<DeathRecipient>* outRecipient = NULL);

  virtual void       attachObject(   const void* objectID,
                                      void* object,
                                      void* cleanupCookie,
                                      object_cleanup_func func);
  virtual void*       findObject(const void* objectID) const;
  virtual void       detachObject(const void* objectID);

  virtual BBinder*   localBinder();

protected:
  virtual             ~BBinder();

  virtual status_t   onTransact( uint32_t code,
                                  const Parcel& data,
                                  Parcel* reply,
                                  uint32_t flags = 0);

private:
                      BBinder(const BBinder& o);
          BBinder&   operator=(const BBinder& o);

  class Extras;

  atomic_uintptr_t   mExtras; // should be atomic<Extras *>
          void*       mReserved0;
};

其中,isBinderAlive函数只是返回true,这很好理解,因为BBinder代表的是Binder通信中的服务端,服务端是否存活,服务端自己当然是知道的。同时linkToDeath和unlinkToDeath这两个函数都只是返回INVALID_OPERATION,表明这两个函数在服务端是不需要做什么的,毕竟这两个函数是用来注册死亡通知用的。

由于是服务端,所以是Client端向服务端发起请求,因此它的核心也有一个transact函数,只是transact的核心却是onTransact函数,只是在onTransact没有什么实际的实现,最终会由子类去具体实现具体的功能。

3.4 JavaBBinder

IBinder是BBinder的父类,BBinder是JavaBBinder的父类。

java层直接与native层交互的对象有两个------Binder对象与BinderProxy对象。

Binder对应"Binder在本进程"的场景,BinderProxy对应"Binder在其他进程"的场景。

native层javaBBinder与java层的Binder一一对应。

native层的BinderProxyNativeData与java层的BinderProxy一一对应。

在native层,gBinderProxyOffsets(binderproxy_offsets_t)存储了java层binderProxy的对象与需要调用的方法和属性。gBinderOffsets(binderproxy_offsets_t)存储了java层binder的对象与需要调用的方法和属性。

ibinderForJavaObject负责通过java的Binder或者BinderProxy对象,找到并返回native层的IBinder对象。

javaObjectForIBinder通过native层的IBinder对象,找到或者封装成java对象返回。

今日分享到此结束,对你有帮助的话,点个赞再走呗,如遇侵权联系删除
关注公众号:Android老皮

解锁 《Android十大板块文档》 ,让学习更贴近未来实战。已形成PDF版

内容如下

1.Android车载应用开发系统学习指南(附项目实战)
2.Android Framework学习指南,助力成为系统级开发高手
3.2023最新Android中高级面试题汇总+解析,告别零offer
4.企业级Android音视频开发学习路线+项目实战(附源码)
5.Android Jetpack从入门到精通,构建高质量UI界面
6.Flutter技术解析与实战,跨平台首要之选
7.Kotlin从入门到实战,全方面提升架构基础
8.高级Android插件化与组件化(含实战教程和源码)
9.Android 性能优化实战+360°全方面性能调优
10.Android零基础入门到精通,高手进阶之路

相关推荐
丘狸尾2 小时前
[cisco 模拟器] ftp服务器配置
android·运维·服务器
van叶~4 小时前
探索未来编程:仓颉语言的优雅设计与无限可能
android·java·数据库·仓颉
Crossoads8 小时前
【汇编语言】端口 —— 「从端口到时间:一文了解CMOS RAM与汇编指令的交汇」
android·java·汇编·深度学习·网络协议·机器学习·汇编语言
li_liuliu9 小时前
Android4.4 在系统中添加自己的System Service
android
C4rpeDime11 小时前
自建MD5解密平台-续
android
鲤籽鲲13 小时前
C# Random 随机数 全面解析
android·java·c#
m0_5485147717 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
凤邪摩羯17 小时前
Android-性能优化-03-启动优化-启动耗时
android
凤邪摩羯17 小时前
Android-性能优化-02-内存优化-LeakCanary原理解析
android
喀什酱豆腐18 小时前
Handle
android