Binder: ServiceManager的获取

2021-01-27 11:44:55 浏览数 (2)

Binder纯理论分析中介绍了Binder的整个通信流程。

下面我们直接通过Service的注册来了解一下Binder的具体工作原理。

我们以MediaService为例,来看下service的注册过程。MediaService对应的启动文件在main_mediaserver.cpp中的main方法。

frameworks/av/media/mediaserver/main_mediaserver.cpp

代码语言:javascript复制
int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);
 
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
    registerExtensions();
    ::android::hardware::configureRpcThreadpool(16, false);
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    ::android::hardware::joinRpcThreadpool();
}

ProcessState

首先创建了ProcessState,它使用了sp的强引用类型。

ProcessState::self内部是一个单例,如果为空它会创建ProcessState对象

代码语言:javascript复制
ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver)) // 启动binder驱动
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mWaitingForThreads(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) // 设置最大线程数
    , mStarvationStartTimeMs(0)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
    , mCallRestriction(CallRestriction::NONE)
{

    if (mDriverFD >= 0) {
        // 映射虚拟内存地址
        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using %s failed: unable to mmap transaction memory.n", mDriverName.c_str());
            close(mDriverFD);
            mDriverFD = -1;
            mDriverName.clear();
        }
    }

    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened.  Terminating.", driver);
}

上面是ProcessState的实例化过程,主要有以下三个重要的设置。

  1. open_driver(driver): 启动binder驱动
  2. mMaxThreads(DEFAULT_MAX_BINDER_THREADS): 设置最大线程数16
  3. mmap: 映射虚拟内存地址
代码语言:javascript复制
static int open_driver(const char *driver)
{
 // 打开binder驱动
    int fd = open(driver, O_RDWR | O_CLOEXEC);
    if (fd >= 0) {
        int vers = 0;
        // 通过ioctl与binder驱动交互,获取binder版本信息
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        if (result == -1) {
            ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
            close(fd);
            fd = -1;
        }
        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
          ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
                vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
            close(fd);
            fd = -1;
        }
        // 设置最大线程数
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        if (result == -1) {
            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
    } else {
        ALOGW("Opening '%s' failed: %sn", driver, strerror(errno));
    }
    return fd;
}

open_driver中通过open打开binder驱动,在binder驱动中对应的方法是binder_open,它会创建binder_proc对象,并将进程等相关信息保存到binder_proc对象中,并返回fd文件描述符。

Linux中通过ioctl方法与设备进行交互,获取binder的版本信息,同时设置binder的最大线程数16。在binder驱动中对应的是binder_ioctl方法,该方法主要通过fd文件描述符、ioctl命令与数据类型来传递数据。

ProcessState创建的过程中,会通过mmap方法,在binder驱动中对应的是binder_mmap方法,将内核中同一块物理内存分别映射到内核的虚拟内存地址空间与用户的虚拟内存地址空间,保证内核空间buffer与用户空间buffer的同步操作。

以上就是ProcessState的主要流程。

下面继续main方法中的下一步操作。

BpServiceManager

代码语言:javascript复制
sp<IServiceManager> sm(defaultServiceManager());

获取IServiceManager对象,所以我们进入defaultServiceManager方法

代码语言:javascript复制
 sp<IServiceManager> defaultServiceManager()
  {
      std::call_once(gSmOnce, []() {
          sp<AidlServiceManager> sm = nullptr;
          while (sm == nullptr) {
              // 重要方法,获取ServiceManager
              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);
              }
          }
          gDefaultServiceManager = new ServiceManagerShim(sm);
      });
      return gDefaultServiceManager;
  }

在该方法中我们发现它会通过interface_cast来获取sm,这里的AidlServiceManager本质就是IServiceManager。我们先把这个方法放一放,先看下它的参数获取

代码语言:javascript复制
ProcessState::self()->getContextObject(nullptr)

嗯,又看到了ProcessState::self(),前面已经分析了,它就是一个ProcessState单例,所以直接看getContextObject方法

代码语言:javascript复制
 
  sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
  {
      sp<IBinder> context = getStrongProxyForHandle(0);
      if (context == nullptr) {
         ALOGW("Not able to get context object on %s.", mDriverName.c_str());
      }
      internal::Stability::tryMarkCompilationUnit(context.get());
      return context;
  }

返回了IBinder,这是我们第一次看到IBinder,感觉有点眉目了,继续看getStrongProxyForHandle(0),注意它这里传了一个参数0

代码语言:javascript复制
 sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
  {
      sp<IBinder> result;
      AutoMutex _l(mLock);
      handle_entry* e = lookupHandleLocked(handle);
      if (e != nullptr) {
          IBinder* b = e->binder;
          if (b == nullptr || !e->refs->attemptIncWeak(this)) {
              if (handle == 0) {
                  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 {
              result.force_set(b);
              e->refs->decWeak(this);
          }
      }
      return result;
  }

IPCThreadState::self()也是一个单例,通过它的transact方法向远端发送数据,关于数据的发送本期不分析,所以我们暂且跳过。

继续,创建了BpBinder,并将handler = 0传给它,最终通过result返回的就是BpBinder(0),此时已经获取到了IBinder,作为跨进程通信的载体。

所以我们向上回退,回到最初的地方interface_cast,现在已经知道它的参数其实就是BpBinder(0),即interface_cast(BpBinder(0))

现在就只剩下interface_cast了,只要我们解开它就能知道ServiceManager是如何创建并获取的。

代码语言:javascript复制
  template<typename INTERFACE>
  inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
  {
      return INTERFACE::asInterface(obj);
  }

发现它调用了INTERFACEasInterface方法,那么INTERFACE又是什么呢?

找了一圈发现它居然是一个模板,声明如下

代码语言:javascript复制
 #define DECLARE_META_INTERFACE(INTERFACE)                               
  public:                                                                 
      static const ::android::String16 descriptor;                        
      static ::android::sp<I##INTERFACE> asInterface(                    
              const ::android::sp<::android::IBinder>& obj);              
      virtual const ::android::String16& getInterfaceDescriptor() const;  
      I##INTERFACE();                                                     
      virtual ~I##INTERFACE();                                           
      static bool setDefaultImpl(std::unique_ptr<I##INTERFACE> impl);    
      static const std::unique_ptr<I##INTERFACE>& getDefaultImpl();      
  private:                                                                
      static std::unique_ptr<I##INTERFACE> default_impl

这里的INTERFACE就是ServiceManager,在模板声明中看到了我们所要的asInterface

下面再看模板函数的具体实现

代码语言:javascript复制
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

 #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)
      const ::android::StaticString16                                     
          I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));
      const ::android::String16 I##INTERFACE::descriptor(                 
          I##INTERFACE##_descriptor_static_str16);                        
      const ::android::String16&                                          
              I##INTERFACE::getInterfaceDescriptor() const {              
          return I##INTERFACE::descriptor;                                
      }                                                                   
      ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              
              const ::android::sp<::android::IBinder>& obj)               
      {                                                                   
          ::android::sp<I##INTERFACE> intr;                               
          if (obj != nullptr) {                                           
              intr = static_cast<I##INTERFACE*>(                          
                  obj->queryLocalInterface(                               
                         I##INTERFACE::descriptor).get());               
             if (intr == nullptr) {                                      
                  intr = new Bp##INTERFACE(obj);                         
             }                                                           
          }                                                               
          return intr;                                                    
      }                      
  ...

INTERFACE替换成ServiceManager来看,最终通过asInterface返回的是BpServiceManager对象,同时它的参数obj对应的就是之前的BpBinder(0)

搞明白这个之后,再回到最初的地方(希望没有晕),对应的就是defaultServiceManager方法。

所以每次调用defaultServiceManager其实就是返回BpServiceManager(BpBinder(0))对象。

最后我们再来看下BpServiceManager,它在IServiceManager.cpp就申明的

代码语言:javascript复制
 class BpServiceManager : public BpInterface<IServiceManager>
  {
  public:
      explicit BpServiceManager(const sp<IBinder>& impl)
          : BpInterface<IServiceManager>(impl)
      {
      } 
   
      virtual sp<IBinder> getService(const String16& name) const
      { ... }
  
      virtual sp<IBinder> checkService( const String16& name) const
      { ... }
  
      virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                  bool allowIsolated, int dumpsysPriority) { ... }
 
   ...
  };

它提供了addServicegetService方法,暂时不分析,但可以大胆猜一下,应该是通过BpServiceManager的这些方法来注册与获取对应的Service。至于它内部又是如何传递到ServiceManager我们后续再分析。

回到最初的main方法,我们接下来应该就是

代码语言:javascript复制
MediaPlayerService::instantiate();

void MediaPlayerService::instantiate() {
 defaultServiceManager()->addService(
  String16("media.player"), new MediaPlayerService());
}

再来看instantiate就简单许多了,它通过defaultServiceManager向其中注册了名称为media.playerMediaPlayerService服务。

defaultServiceManager对应的是BpServiceManager(BpBinder(0)),所以上面我们的猜想是成立的。关于服务的注册、验证与获取都是通过BpServiceManager代理完成的,其实内部最终都是通过BpBinder(0)来传输的。

好了,为了尽量缩短篇幅,降低阅读疲劳,提升读者体验,这篇文章就分析到这里。

下面来总结一下MediaService所做的一部分核心内容

  1. 创建ProcessState对象
  2. ProcessState的创建过程中启动binder驱动,使用ioctlbinder驱动交互,并设置binder最大并发线程数16,使用mmap映射虚拟内存地址
  3. 创建IPCThreadState对象,使用transactserver端发送数据
  4. 创建BpBinder对象,获取IBinder,作为跨进程通信的载体
  5. 创建BpServiceManager对象,作为服务注册、检验与获取的代理

0 人点赞