百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

Android 12 系统源码分析 | Native Binder 代码变迁

yuyutoo 2024-10-11 23:55 1 浏览 0 评论

作者:秋城

注:广义上 Native Binder 可理解为包含 vnd,hw,rpc 等内容,本文所讨论的Native Binder 指的仅是 servicemanager 服务程序及 libbinder 中相关代码,不做广义的延伸

一、前言

Servicemanager 程序(以下简称SM)是 Android 系统 binder 模块重要的组成部分,扮演着类似 C/S 架构中的 DNS 服务器的角色,提供服务增查和权限管理等功能支撑

在 Android 11 之前的版本里,SM 是面向 binder 驱动编程,直接使用 open、mmap、ioctl 等 api 与 binder 驱动交互。而从 Android 11 开始,SM 放弃使用这些较底层的接口,转向 libbinder 库和 AIDL。标志性的提交如下,该提交奠定了新的 SM 架构基础,此后多次提交对此进行完善填充

frameworks/native

servicemanager: use libbinder

Bug: 135768100
Test: boot
Test: servicemanager_test

Change-Id: I9d657b6c0d0be0f763b6d54e0e6c6bc1c1e3fc7a
(cherry picked from commit 3e092daa14c63831d76d3ad6e56b2919a0523536)

本文代码基于 Android 12,以 SM 为主视角,从架构和情景流程上带大家认识新的 Native Binder

二. 软件架构

2.1 架构概述

图1:切换到 aidl 和 libbinder 后的 ServiceManager 类关系图

图注:

为了画图方便,将 namespace 写成了下划线形式。

android_os_BpServiceManager 和 android_os_BnServiceManager、android_os_IServiceManager 类均在 android os 的 namespace 中,其他无下划线的类名,处于 android namespace 中。

一图胜千言,11 之前的 SM 是写在 c 文件里,没有类的概念,现在基于 aidl 和 libbinder,使用 cpp 语言,用 uml 就可以很形象地展示类关系了。就着这幅图我们大致描述新的软件架构

  • 红色线段大概地将服务端与客户端类相分隔,服务端在右下角

一些 libbinder 的用于继承的公共类请读者自行剥离,而不是将其归入某一端。例如 IBinder,我们知道他是 BBinder 和 BpBinder 的父类,是公共的接口约束

  • libbinder 中客户端的入口变为:IServiceManager.cpp#ServiceManagerShim

之前无该辅助类,而是直接操作 BpServiceManager,这个辅助类封装了 aidl 自动生成的 BpServiceManager,所以现在的客户端代码流就变成如下三步:

1.用户代码
2.libbinder代码 binder/IServiceManager.cpp#ServiceManagerShim
3.aidl代码      android/os/IServiceManager.cpp#BpServiceManager接口

所以 libbinder 中的 ServiceManagerShim 起到了一个中转的作用,把请求转给 out 下 aidl 自动生成的 BpServiceManager

  • BpServiceManager 的实现挪到 out

原来是在 libbinder#IServiceManager.cpp 中手写实现,现在是 aidl 帮你实现。

当然,该文件中同样自动实现了 BnServiceManager 类

代码路径

out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm64_armv8-a_shared/gen/aidl/android/os/IServiceManager.cpp

  • 服务端的核心实现在 ServiceManager.cpp

原来是没有 Bn 的,而是一个 binder_loop 方法沟通驱动,现在则是ServiceManager 继承了 BnServiceManager 来获得代码流。

  • waitForService 的改动:IServiceCallback.aidl

Waiter 类。新增了 binder 匿名服务用来向 sm 注册跨进程的回调,当 sm 检测到有服务注册时,会返回通知

  • 服务的客户端数量监听:IServiceCallback.aidl

IServiceCallback.aidl 这个匿名 binder 服务就是用于该目的,可以监听某个服务的客户端数量

2.2、文件路径

  • AIDL

AIDL 是一种方便的接口定义语言,用于 Binder-IPC 编程。详细介绍与使用可参考:AIDL Overview

我们关注三个 aidl,分别是 IServiceManager.aidl、IServiceCallback.aidl、IClientCallback.aidl,对应的编译后生成的文件路径为:

out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/

IClientCallback.cpp

IServiceCallback.cpp

IServiceManager.cpp

  • libbinder 中的代码路径

frameworks/native/libs/binder/IServiceManager.cpp

  • SM 服务端代码路径

frameworks/native/cmds/servicemanager/

main.cpp

Access.cpp

ServiceManager.cpp

本小节仅展示涉及变迁的文件路径。简洁起见只写了 cpp 文件,对应的 h 头文件可以附近查找。

另外需要特别区分的是,有两个 IServiceManager。

一个在 libbinder 中,是 Android 的 name space,直接被用户#include<binder/IServiceManager>使用。

另一个是 aidl 自动生成的 Android os 的 name space,被上面的 libbinder 所使#include<android/os/IServiceManager>

2.3、小结

第二章节从全局的角度展示了 SM 切换到 aidl 和 libbinder的软件架构,结合图来看还是非常清楚易于理解的

接下来跟踪几个情景流程,展示新架构中的细节

三 servicemanager 启动流程分析

图2:servicemanager 启动时序图

如上图,启动流程的变动主要在进入循环的方式,Android 11 之前是通过binder_loop方法,而现在是通过 looper。下面展示细节

frameworks/native/cmds/servicemanager/main.cpp

int main(int argc, char** argv) {
   if (argc > 2) {
       LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
  }

   const char* driver = argc == 2 ? argv[1] : "/dev/binder";
//沟通binder驱动,open,mmap
   sp<ProcessState> ps = ProcessState::initWithDriver(driver);
   ps->setThreadPoolMaxThreadCount(0);
   //oneway限制,sm发起的binder调用必须是单向,否则打印堆栈日志提示
   ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
   //实例化ServiceManager,传入Access类用于鉴权
   sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
   if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
       LOG(ERROR) << "Could not self register servicemanager";
  }
   //设置全局变量给IPCThreadState
   IPCThreadState::self()->setTheContextObject(manager);
   //注册到驱动,成为binder管理员,handle是0
   ps->becomeContextManager();
   //准备looper
   sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
   //通知驱动BC_ENTER_LOOPER,监听驱动fd,有消息时回调到handleEvent处理binder调用
   BinderCallback::setupTo(looper);
   //服务的注册监听相关
   ClientCallbackCallback::setupTo(looper, manager);
   //无限循环等消息
   while(true) {
       looper->pollAll(-1);
  }

   // should not be reached
   return EXIT_FAILURE;
}

和原来的 servicemanager 服务相比较,使用了 libbinder 后,代码更规范化,和其他 native 的服务风格一致了。

  • 之前是直接 open、mmap 现在是借助 libbinder
  • 之前是 binder_loop死 循环接收驱动的消息,现在是通过 looper 监听 fd 来handleEvent
  • 之前的鉴权现在被独立到单独文件 Access.cpp

突然想起一个题目,servicemanager 映射的虚拟内存有多大?现在的答案是和普通应用一样大:1M-2 页。

frameworks/native/libs/binder/ProcessState.cpp

#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)

启动流程比较清晰不多赘述,下一小节看 addService 的流程。

四、addService 流程分析

图3:defaultServiceManager流程

图4:addService 客户端流程

图5:addService 服务端流程

先上图,总览 native 的代码流程,客户端是 libbinder 里的 IServiceManager.cpp,服务端是我们的 ServiceManager.cpp

4.1 ServiceManagerShim::addService

frameworks/native/libs/binder/IServiceManager.cpp

status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
                                       bool allowIsolated, int dumpsysPriority)
{
   Status status = mTheRealServiceManager->addService(
       String8(name).c_str(), service, allowIsolated, dumpsysPriority);
   return status.exceptionCode();
}

直接使用的 mTheRealServiceManager,澄清疑问,mTheRealServiceManager 是谁?

4.1.1 mTheRealServiceManager 是谁?

frameworks/native/libs/binder/IServiceManager.cpp

#include <android/os/IServiceManager.h>
using AidlServiceManager = android::os::IServiceManager;
class ServiceManagerShim : public IServiceManager
{
protected:
   sp<AidlServiceManager> mTheRealServiceManager;
......
ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl)
: mTheRealServiceManager(impl)
{}

可以看到,mTheRealServiceManager 就是一个 android::os::IServiceManager 类型的实例,并且在 ServiceManagerShim 实例化时赋值。

那么 ServiceManagerShim 何时实例化呢?答案是 defaultServiceManager() 中

frameworks/native/libs/binder/IServiceManager.cpp

sp<IServiceManager> defaultServiceManager()
{
   std::call_once(gSmOnce, []() {
       sp<AidlServiceManager> sm = nullptr;
       while (sm == nullptr) {
           //1、拿到AidlServiceManager类型的BpServiceManager(new BpBinder(0))实例
           sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
           if (sm == nullptr) {
               ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str());
               sleep(1);
          }
      }
       //2、new ServiceManagerShim
       gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
  });

   return gDefaultServiceManager;
}

如注释1、2,mTheRealServiceManager 就是在这样流程中赋值的。他的真是面目是BpServiceManager(new BpBinder(0))

由图1可知,我们拿到了操作 binder 驱动的入口,BpServiceManager-->BpBinder-->IPCThreadState-->ioctl

关于一部分旧知识会贴拓展链接本文不做展开。interface_cast 的实现可参考:浅谈 Android 系统进程间通信(IPC)机制Binder 中的 Server 和 Client 获得 Service Manager 接口之路

好现在返回上节,直接走入 BpServiceManager#addService 方法

4.2 BpServiceManager::addService

out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IServiceManager.cpp

namespace android {
namespace os {

BpServiceManager::BpServiceManager(const ::android::sp<::android::IBinder>& _aidl_impl)
  : BpInterface<IServiceManager>(_aidl_impl){//_aidl_impl就是BpBinder(0)实例
}
--------------------------------------------------
  ::android::binder::Status BpServiceManager::addService(const ::std::string& name, const ::android::sp<::android::IBinder>& service, bool allowIsolated, int32_t dumpPriority) {
::android::Parcel _aidl_data;
 _aidl_data.markForBinder(remoteStrong());//0、和rpc binder有关
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
 //1、写interface
 _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
 if (((_aidl_ret_status) != (::android::OK))) {
   goto _aidl_error;
}
 //2、写name
 _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
 if (((_aidl_ret_status) != (::android::OK))) {
   goto _aidl_error;
}
 //3、写binder对象
 _aidl_ret_status = _aidl_data.writeStrongBinder(service);
 if (((_aidl_ret_status) != (::android::OK))) {
   goto _aidl_error;
}
 //4、写allowIsolated
 _aidl_ret_status = _aidl_data.writeBool(allowIsolated);
 if (((_aidl_ret_status) != (::android::OK))) {
   goto _aidl_error;
}
 //5、写dumpPriority
 _aidl_ret_status = _aidl_data.writeInt32(dumpPriority);
 if (((_aidl_ret_status) != (::android::OK))) {
   goto _aidl_error;
}
 //6、借助BpBinder(0)-transact来发起binder通信
 _aidl_ret_status = remote()->transact(BnServiceManager::TRANSACTION_addService, _aidl_data, &_aidl_reply, 0);
 if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IServiceManager::getDefaultImpl())) {
    return IServiceManager::getDefaultImpl()->addService(name, service, allowIsolated, dumpPriority);
}
 if (((_aidl_ret_status) != (::android::OK))) {
   goto _aidl_error;
}
 //7、如果有返回值就从这个parcel包里读
 _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
 if (((_aidl_ret_status) != (::android::OK))) {
   goto _aidl_error;
}
 if (!_aidl_status.isOk()) {
   return _aidl_status;
}
 _aidl_error:
 _aidl_status.setFromStatusT(_aidl_ret_status);
 return _aidl_status;
}

把 Android 10 的贴上来,我们对比看看

frameworks/native/libs/binder/IServiceManager.cpp

   virtual status_t addService(const String16& name, const sp<IBinder>& service,
                               bool allowIsolated, int dumpsysPriority) {
       Parcel data, reply;
       data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
       data.writeString16(name);
       data.writeStrongBinder(service);
       data.writeInt32(allowIsolated ? 1 : 0);
       data.writeInt32(dumpsysPriority);
       status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
       return err == NO_ERROR ? reply.readExceptionCode() : err;
  }

和11之前手写的 BpServiceManager 相比,本质是没变的,就是多了些花里胡哨的规范性代码。

到这里,客户端的代码就大致展示完了,transact 再往后就是旧有的流程,可参考:浅谈 Android 系统进程间通信(IPC)机制 Binder 中的 Server 和 Client 获得Service Manager 接口之路

之后走到 binder 驱动,驱动又根据 handle == 0 找到对端,我们的 servicemanager 进程,唤醒他开始处理请求。

4.3 BinderCallback::handleEvent

如图4:addService 服务端流程,现在开始服务端的流程展示

frameworks/native/cmds/servicemanager/main.cpp

class BinderCallback : public LooperCallback {
public:
......
       int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
       IPCThreadState::self()->handlePolledCommands();
       return 1;  // Continue receiving callbacks.
  }
};

之后走到 BR_TRANSACTION

frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::executeCommand(int32_t cmd)
{
switch ((uint32_t)cmd) {
case BR_TRANSACTION:
      {
      if (tr.target.ptr) {
      //因为目的端sm所以是tr.target.ptr是0
      }else {//开始业务分发
          error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
      }

the_context_object 是 SM 启动的时候设置好的

sp<BBinder> the_context_object;

void IPCThreadState::setTheContextObject(const sp<BBinder>& obj)
{
   the_context_object = obj;
}

是 ServiceManager 类实例,所以也是一个 BBinder 对象,所以就有了 transact()-->onTransact() 的处理能力。

所以现在the_context_object->transact()调用就走到 BBinder 的 transact 又走到BnServiceManager的onTransact()方法,回到了这个aidl自动生成的IServiceManager.cpp文件里

兜兜转转还是在这个文件

out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IServiceManager.cpp

::android::status_t BnServiceManager::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
::android::status_t _aidl_ret_status = ::android::OK;
 switch (_aidl_code) {
 case BnServiceManager::TRANSACTION_addService:
{
  ::std::string in_name;
  ::android::sp<::android::IBinder> in_service;
   bool in_allowIsolated;
   int32_t in_dumpPriority;
   //检查interface
   if (!(_aidl_data.checkInterface(this))) {
     _aidl_ret_status = ::android::BAD_TYPE;
     break;
  }
   //读name
   _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
   if (((_aidl_ret_status) != (::android::OK))) {
     break;
  }
   //读binder
   _aidl_ret_status = _aidl_data.readStrongBinder(&in_service);
   if (((_aidl_ret_status) != (::android::OK))) {
     break;
  }
   //读in_allowIsolated
   _aidl_ret_status = _aidl_data.readBool(&in_allowIsolated);
   if (((_aidl_ret_status) != (::android::OK))) {
     break;
  }
   //读in_dumpPriority
   _aidl_ret_status = _aidl_data.readInt32(&in_dumpPriority);
   if (((_aidl_ret_status) != (::android::OK))) {
     break;
  }
   //调用真正的ServiceManager.cpp中的实现
  ::android::binder::Status _aidl_status(addService(in_name, in_service, in_allowIsolated, in_dumpPriority));
   //如果有返回写返回到_aidl_reply
   _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
   if (((_aidl_ret_status) != (::android::OK))) {
     break;
  }
   if (!_aidl_status.isOk()) {
     break;
  }
}

和Bp端是对称的操作,下一步走到 ServiceManager.cpp::addService 方法

4.4 ServiceManager::addService

frameworks/native/cmds/servicemanager/ServiceManager.cpp



Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
   auto ctx = mAccess->getCallingContext();

   // uid鉴权
   if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
       return Status::fromExceptionCode(Status::EX_SECURITY);
  }
   //selinux鉴权
   if (!mAccess->canAdd(ctx, name)) {
       return Status::fromExceptionCode(Status::EX_SECURITY);
  }

   if (binder == nullptr) {
       return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
  }
   //检查name命名
   if (!isValidServiceName(name)) {
       LOG(ERROR) << "Invalid service name: " << name;
       return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
  }
   //如果vndservicemanager则检查VINTF manifest
#ifndef VENDORSERVICEMANAGER
   if (!meetsDeclarationRequirements(binder, name)) {
       // already logged
       return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
  }
#endif  // !VENDORSERVICEMANAGER
   //和rpc有关,死亡监听
   // implicitly unlinked when the binder is removed
   if (binder->remoteBinder() != nullptr &&
       binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
       LOG(ERROR) << "Could not linkToDeath when adding " << name;
       return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
  }
   //新增一个结构体到map中
   // Overwrite the old service if it exists
   mNameToService[name] = Service {
      .binder = binder,
      .allowIsolated = allowIsolated,
      .dumpPriority = dumpPriority,
      .debugPid = ctx.debugPid,
  };
   //架构中提到的waiteForService的跨进程
   auto it = mNameToRegistrationCallback.find(name);
   if (it != mNameToRegistrationCallback.end()) {
       for (const sp<IServiceCallback>& cb : it->second) {
           mNameToService[name].guaranteeClient = true;
           // permission checked in registerForNotifications
           cb->onRegistration(name, binder);
      }
  }

   return Status::ok();
}

五、其他值得关注的细节

前两节是全局总览、经典情景的视角看代码,现在我们换一个视角,展示一些边边角角的内容为上面的主干填充细节。

5.1 Servicemanager 的能力变化

Android 11 之前仅有 4 种接口暴露给应用

frameworks/native/libs/binder/include/binder/IServiceManager.h

  enum {
      GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
      CHECK_SERVICE_TRANSACTION,
      ADD_SERVICE_TRANSACTION,
      LIST_SERVICES_TRANSACTION,
  };

而 Android 11 增加到9个,Android 12 又增加到 13 个

out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/BnServiceManager.h

class BnServiceManager : public ::android::BnInterface<IServiceManager> {
public:
 static constexpr uint32_t TRANSACTION_getService = ::android::IBinder::FIRST_CALL_TRANSACTION + 0;
 static constexpr uint32_t TRANSACTION_checkService = ::android::IBinder::FIRST_CALL_TRANSACTION + 1;
 static constexpr uint32_t TRANSACTION_addService = ::android::IBinder::FIRST_CALL_TRANSACTION + 2;
 static constexpr uint32_t TRANSACTION_listServices = ::android::IBinder::FIRST_CALL_TRANSACTION + 3;
 static constexpr uint32_t TRANSACTION_registerForNotifications = ::android::IBinder::FIRST_CALL_TRANSACTION + 4;
 static constexpr uint32_t TRANSACTION_unregisterForNotifications = ::android::IBinder::FIRST_CALL_TRANSACTION + 5;
 static constexpr uint32_t TRANSACTION_isDeclared = ::android::IBinder::FIRST_CALL_TRANSACTION + 6;
 static constexpr uint32_t TRANSACTION_getDeclaredInstances = ::android::IBinder::FIRST_CALL_TRANSACTION + 7;
 static constexpr uint32_t TRANSACTION_updatableViaApex = ::android::IBinder::FIRST_CALL_TRANSACTION + 8;
 static constexpr uint32_t TRANSACTION_getConnectionInfo = ::android::IBinder::FIRST_CALL_TRANSACTION + 9;
 static constexpr uint32_t TRANSACTION_registerClientCallback = ::android::IBinder::FIRST_CALL_TRANSACTION + 10;
 static constexpr uint32_t TRANSACTION_tryUnregisterService = ::android::IBinder::FIRST_CALL_TRANSACTION + 11;
 static constexpr uint32_t TRANSACTION_getServiceDebugInfo = ::android::IBinder::FIRST_CALL_TRANSACTION + 12;

从这些接口的变动我们也可以很清晰地把握住 servicemanager 的前进方向

5.2 DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE

frameworks/native/libs/binder/include/binder/IInterface.h

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
   static_assert(internal::allowedManualInterface(NAME),               \
                 "b/64223827: Manually written binder interfaces are " \
                 "considered error prone and frequently have bugs. "   \
                 "The preferred way to add interfaces is to define "   \
                 "an .aidl file to auto-generate the interface. If "   \
                 "an interface must be manually written, add its "     \
                 "name to the whitelist.");                           \
   DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)   \
-----------------------------
constexpr const char* const kManualInterfaces[] = {
 "android.app.IActivityManager",
 "android.app.IUidObserver",
 "android.drm.IDrm",
 "android.dvr.IVsyncCallback",
 "android.dvr.IVsyncService",
 "android.gfx.tests.ICallback",
 "android.gfx.tests.IIPCTest",
......

以后手写的 native 服务需要关注下这个宏,做了限制。谷歌建议是现在的 native服务都用 aidl,别手写

5.3 String16、String8 与 name

aidl 改造之前,都是一路 String16 从客户端传到服务端,而现在需要绕一些路了。还是以 addService 为例

status_t ServiceManagerShim::addService(const String16& name,){
   Status status = mTheRealServiceManager->addService(
       String8(name).c_str(), );
在这里转一次,16转成8
------------------------------------------
_aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
在BpServiceManager里又转了一次,8转16
------------------------------------------
_aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
现在来到BnServiceManager继续转,16转8

转来转去快晕了。总结就是,SM 服务端都是操作的 utf8,而 libbinder 客户端都是 utf16。有修改的话需要注意下编码问题

也可能是由于这个转换问题,在服务端加了个服务名检查

bool isValidServiceName(const std::string& name) {
   if (name.size() == 0) return false;
   if (name.size() > 127) return false;

   for (char c : name) {
       if (c == '_' || c == '-' || c == '.' || c == '/') continue;
       if (c >= 'a' && c <= 'z') continue;
       if (c >= 'A' && c <= 'Z') continue;
       if (c >= '0' && c <= '9') continue;
       return false;
  }

   return true;
}

5.4 服务保存的数据结构

SM 需要保存服务及其对应的信息,Android 11 前用的链表 svc_list,成员是 svc_info 结构体;Android 11 后用的 map,成员也是结构体

frameworks/native/cmds/servicemanager/ServiceManager.h

   struct Service {
       sp<IBinder> binder; // not null
       bool allowIsolated;
       int32_t dumpPriority;
       bool hasClients = false; // notifications sent on true -> false.
       bool guaranteeClient = false; // forces the client check to true
       pid_t debugPid = 0; // the process in which this service runs

       // the number of clients of the service, including servicemanager itself
       ssize_t getNodeStrongRefCount();
  };
   using ServiceMap = std::map<std::string, Service>;
   ServiceMap mNameToService;

这个 Service 结构体有了更多的信息和能力,getNodeStrongRefCount() 方法可以获取该服务有多少个客户端

5.5 listServices 返回值

Android 11 之前的实现是客户端循环 checkService,Android 11 之后是直接返回的是 std::vector

  • 客户端

frameworks/native/libs/binder/IServiceManager.cpp

Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority)
{
   std::vector<std::string> ret;
   if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
       return {};
  }

   Vector<String16> res;
   res.setCapacity(ret.size());
   for (const std::string& name : ret) {
       res.push(String16(name.c_str()));
  }
   return res;
}
  • 服务端

frameworks/native/cmds/servicemanager/ServiceManager.cpp

Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::string>* outList) {
   size_t toReserve = 0;
   for (auto const& [name, service] : mNameToService) {
      (void) name;

       if (service.dumpPriority & dumpPriority) ++toReserve;
  }

   outList->reserve(toReserve);
   for (auto const& [name, service] : mNameToService) {
      (void) service;

       if (service.dumpPriority & dumpPriority) {
           outList->push_back(name);
      }
  }

这里也可以看到字符编码的问题,客户端用的是 utf16,而服务端用的是 utf8

  • 顺便提一嘴 dumpsys 的画蛇添足的修改

frameworks/native/cmds/dumpsys/dumpsys.cpp

    if (services.empty() || showListOnly) {
        services = listServices(priorityFlags, asProto);                                                                        
......
    if (N > 1) {
        for (size_t i=0; i<N; i++) {
            sp<IBinder> service = sm_->checkService(services[i]);

获取到服务列表后为什么再循环 check 一遍呢?我感觉是没有必要的。

5.6 waitForService 与 IServiceCallback.aidl

利用了匿名 binder 来传递回调,有兴趣可以自己看看

  • 回调注册

frameworks/native/libs/binder/IServiceManager.cpp

sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
{
 class Waiter : public android::os::BnServiceCallback {
       Status onRegistration(const std::string& /*name*/,
                             const sp<IBinder>& binder) override {
......
    sp<Waiter> waiter = sp<Waiter>::make();
    if (Status status = mTheRealServiceManager->registerForNotifications(name, waiter);
  • 回调响应

frameworks/native/cmds/servicemanager/ServiceManager.cpp

Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
auto it = mNameToRegistrationCallback.find(name);
   if (it != mNameToRegistrationCallback.end()) {
       for (const sp<IServiceCallback>& cb : it->second) {
           mNameToService[name].guaranteeClient = true;
           // permission checked in registerForNotifications
           cb->onRegistration(name, binder);
      }
  }
  • aidl 及其生成的代码位置

frameworks/native/libs/binder/aidl/android/os/IServiceCallback.aidl

out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IServiceCallback.cpp

5.7 IClientCallback.aidl

IServiceManager.aidl 中定义的接口,都是在#include <binder/IServiceManager.h>吗?答案为否。IClientCallback 就是这样一个例子

想用 registerClientCallback 方法注册回调,需要直接使用#include <android/os/IServiceManager.h>拿到 BpServiceManager 实例,来通信

这个接口没有暴露在 libbinder 的 IServiceManager 中

这个回调用于监听某个服务有 client,和 IServiceCallback.aidl 一样是匿名 binder服务,一个例子 LazyServiceRegistrar.cpp,可自行了解。

代码路径

frameworks/native/libs/binder/aidl/android/os/IClientCallback.aidl

frameworks/native/libs/binder/LazyServiceRegistrar.cpp

out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IClientCallback.cpp

frameworks/native/cmds/servicemanager/ServiceManager.cpp

六、总结

  • SM 经过 aidl 和 libbinder 改造后,对于开发者来说,修改会更加规范和省心
  • 新引入的特性展示了 SM 功能更多的可能性,可为特定需求提供思路,native aidl和匿名 binder 回调值得学习

相关推荐

jQuery VS AngularJS 你更钟爱哪个?

在这一次的Web开发教程中,我会尽力解答有关于jQuery和AngularJS的两个非常常见的问题,即jQuery和AngularJS之间的区别是什么?也就是说jQueryVSAngularJS?...

Jquery实时校验,指定长度的「负小数」,小数位未满末尾补0

在可以输入【负小数】的输入框获取到焦点时,移除千位分隔符,在输入数据时,实时校验输入内容是否正确,失去焦点后,添加千位分隔符格式化数字。同时小数位未满时末尾补0。HTML代码...

如何在pbootCMS前台调用自定义表单?pbootCMS自定义调用代码示例

要在pbootCMS前台调用自定义表单,您需要在后台创建表单并为其添加字段,然后在前台模板文件中添加相关代码,如提交按钮和表单验证代码。您还可以自定义表单数据的存储位置、添加文件上传字段、日期选择器、...

编程技巧:Jquery实时验证,指定长度的「负小数」

为了保障【负小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【负小数】的方法。HTML代码<inputtype="text"class="forc...

一篇文章带你用jquery mobile设计颜色拾取器

【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...

编程技巧:Jquery实时验证,指定长度的「正小数」

为了保障【正小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【正小数】的方法。HTML做成方法<inputtype="text"class="fo...

jquery.validate检查数组全部验证

问题:html中有多个name[],每个参数都要进行验证是否为空,这个时候直接用required:true话,不能全部验证,只要这个数组中有一个有值就可以通过的。解决方法使用addmethod...

Vue进阶(幺叁肆):npm查看包版本信息

第一种方式npmviewjqueryversions这种方式可以查看npm服务器上所有的...

layui中使用lay-verify进行条件校验

一、layui的校验很简单,主要有以下步骤:1.在form表单内加上class="layui-form"2.在提交按钮上加上lay-submit3.在想要校验的标签,加上lay-...

jQuery是什么?如何使用? jquery是什么功能组件

jQuery于2006年1月由JohnResig在BarCampNYC首次发布。它目前由TimmyWilson领导,并由一组开发人员维护。jQuery是一个JavaScript库,它简化了客户...

django框架的表单form的理解和用法-9

表单呈现...

jquery对上传文件的检测判断 jquery实现文件上传

总体思路:在前端使用jquery对上传文件做部分初步的判断,验证通过的文件利用ajaxFileUpload上传到服务器端,并将文件的存储路径保存到数据库。<asp:FileUploadI...

Nodejs之MEAN栈开发(四)-- form验证及图片上传

这一节增加推荐图书的提交和删除功能,来学习node的form提交以及node的图片上传功能。开始之前需要源码同学可以先在git上fork:https://github.com/stoneniqiu/R...

大数据开发基础之JAVA jquery 大数据java实战

上一篇我们讲解了JAVAscript的基础知识、特点及基本语法以及组成及基本用途,本期就给大家带来了JAVAweb的第二个知识点jquery,大数据开发基础之JAVAjquery,这是本篇文章的主要...

推荐四个开源的jQuery可视化表单设计器

jquery开源在线表单拖拉设计器formBuilder(推荐)jQueryformBuilder是一个开源的WEB在线html表单设计器,开发人员可以通过拖拉实现一个可视化的表单。支持表单常用控件...

取消回复欢迎 发表评论: