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零基础入门到精通,高手进阶之路

相关推荐
林十一npc3 分钟前
MySQL索引与视图综合应用示例解析
android·前端·mysql
QING6182 小时前
Kotlin containsValue用法及代码示例
android·kotlin·源码阅读
QING6182 小时前
Kotlin coerceAtMost用法及代码示例
android·kotlin·源码阅读
QING6182 小时前
Kotlin commonSuffixWith用法及代码示例
android·kotlin·源码阅读
QING6182 小时前
Kotlin coerceAtLeast用法及代码示例
android·kotlin·源码阅读
光军oi3 小时前
Mysql从入门到精通day5————子查询精讲
android·数据库·mysql
鸿蒙布道师12 小时前
鸿蒙NEXT开发Base64工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
jiet_h12 小时前
Android adb 的功能和用法
android·adb
美狐美颜sdk13 小时前
美颜SDK兼容性挑战:如何让美颜滤镜API适配iOS与安卓?
android·深度学习·ios·美颜sdk·第三方美颜sdk·视频美颜sdk
居然是阿宋13 小时前
深入理解 YUV 颜色空间:从原理到 Android 视频渲染
android·音视频