前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Binder: addService初探

Binder: addService初探

作者头像
Rouse
发布2021-02-23 15:06:21
5510
发布2021-02-23 15:06:21
举报
文章被收录于专栏:Android补给站Android补给站

Binder: ServiceManager的获取文章中,分析了ProcessStateIPCThreadState的创建过程。最后在defaultServiceManager中,返回的是持有BpBinderBpServiceManager对象。

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

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

所以在instantiate方法中调用的addService其实是BpServiceManager中的方法,将名称为media.playerMediaPlayerService对象进行注册

addService

下面我们直接看BpServiceManager中的addService

代码语言:javascript
复制
virtual status_t addService(const String16& name, const sp<IBinder>& service,
                          bool allowIsolated, int dumpsysPriority) {
  // 封装成Parcel对象
  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;
}

这里将数据统一封装到Parcel对象中,最后通过remote()transact方法将数据传输到远端,对应的codeADD_SERVICE_TRANSACTION

现在我们在来看下remote()到底是什么。

它是BpServiceManager中的一个方法,这个方法来自于它的父类

代码语言:javascript
复制
class BpServiceManager : public BpInterface<IServiceManager>

public:
  explicit BpServiceManager(const sp<IBinder>& impl) // BpBinder(0)
      : BpInterface<IServiceManager>(impl) {}
 
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote) : BpRefBase(remote)
 
BpRefBase::BpRefBase(const sp<IBinder>& o) : mRemote(o.get()), mRefs(nullptr), mState(0)

class BpRefBase : public virtual RefBase
{
protected:
  explicit                BpRefBase(const sp<IBinder>& o);
  virtual                 ~BpRefBase();
  virtual void            onFirstRef();
  virtual void            onLastStrongRef(const void* id);
  virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);

  inline  IBinder*        remote()                { return mRemote; }
  inline  IBinder*        remote() const          { return mRemote; }

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

  IBinder* const          mRemote;
  RefBase::weakref_type*  mRefs;
  std::atomic<int32_t>    mState;
};

从上面继承流程可以得到这个remote()返回的就是mRemote,而mRemote其实是最开始的参数BpBinder(0)。说明这里调用的是BpBindertransact方法

代码语言:javascript
复制
status_t BpBinder::transact(
  uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
  // Once a binder has died, it will never come back to life.
  if (mAlive) {
      status_t status = IPCThreadState::self()->transact(
          mHandle, code, data, reply, flags);
      if (status == DEAD_OBJECT) mAlive = 0;
      return status;
  }

  return DEAD_OBJECT;
}

进入BpBinder发现又转调到IPCThreadStatetransact方法

代码语言:javascript
复制
status_t IPCThreadState::transact(int32_t handle,
                                uint32_t code, const Parcel& data,
                                Parcel* reply, uint32_t flags)
{

  ...

  // 传输数据
  err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);

  if ((flags & TF_ONE_WAY) == 0) {

      ...
      
      if (reply) {
          // 等待远程数据的返回
          err = waitForResponse(reply);
      } else {
          Parcel fakeReply;
          err = waitForResponse(&fakeReply);
      }

  } else {
      err = waitForResponse(nullptr, nullptr);
  }

  return err;
}

这里主要做的就两件事

  1. 通过writeTransactionData将数据写入到Parcel中,对应的cmd命令为BC_TRANSACTION,这是请求码,对应的都是以BC_开头命名,在service端会通过这些请求码做不同的逻辑处理。
  2. 通过waitForResponse来等待远端的数据返回,这里也有一个cmd命令行,例如BR_REPLY,这是返回码,对应的都是以BR_开头命名的,在client也会通过这些返回码做不同的逻辑处理。

今天我们不研究这几个方法,后续文章会专门分析数据的交互。

到这里MediaPlayerService已经注册完毕,我们接下最前面的main方法继续往下走。

startThreadPool

代码语言:javascript
复制
ProcessState::self()->startThreadPool();

又是ProcessState中的方法,进入startThreadPooll中看一下。

代码语言:javascript
复制
void ProcessState::startThreadPool()
{
  AutoMutex _l(mLock);
  if (!mThreadPoolStarted) {
      mThreadPoolStarted = true;
      spawnPooledThread(true);
  }
}
 
void ProcessState::spawnPooledThread(bool isMain)
{
  if (mThreadPoolStarted) {
      String8 name = makeBinderThreadName();
      // 开启binder线程池
      sp<Thread> t = new PoolThread(isMain);
      t->run(name.string());
  }
}

spawnPooledThread方法中创建了PoolThread线程池,它继承于Thread,最后调用了线程的run方法

joinThreadPool

代码语言:javascript
复制
IPCThreadState::self()->joinThreadPool();

继续看joinThreadPooll方法, 它在IPCThreadState

代码语言:javascript
复制
void IPCThreadState::joinThreadPool(bool isMain)
{

  mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

  status_t result;
  do {
      processPendingDerefs();
      // 等待命令行的到来
      result = getAndExecuteCommand();
  } while (result != -ECONNREFUSED && result != -EBADF);

  mOut.writeInt32(BC_EXIT_LOOPER);
  // 与binder驱动通信
  talkWithDriver(false);
}

这里主要的方法是getAndExecuteCommand(),它是用来处理接收service端发送过来的数据,因为serviceclient是可以互相发起数据的交互。这个时候client就相当于service,它开启轮询不断地监听service发过来的数据。最终它会调用executeCommand来统一处理。

代码语言:javascript
复制

status_t IPCThreadState::executeCommand(int32_t cmd)
{

  switch ((uint32_t)cmd) {

  ...

  case BR_TRANSACTION_SEC_CTX:
  case BR_TRANSACTION:
      {
          ...

          if (tr.target.ptr) {
              if (reinterpret_cast<RefBase::weakref_type*>(
                      tr.target.ptr)->attemptIncStrong(this)) {
                  // BBinder
                  error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                          &reply, tr.flags);
                  reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
              } else {
                  error = UNKNOWN_TRANSACTION;
              }

          } else {
              error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
          }
          
          ...

          if ((tr.flags & TF_ONE_WAY) == 0) {
              // 向服务端发送回应reply,注意这里的0,特定标识;
              sendReply(reply, 0);
          } else {
              LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
          }

          ...

      }
      break;

  ...

  default:
      ALOGE("*** BAD COMMAND %d received from Binder driver\n", cmd);
      result = UNKNOWN_ERROR;
      break;
  }

  if (result != NO_ERROR) {
      mLastError = result;
  }

  return result;
}

为了简化代码只展示了主要的一部分代码,BR_TRANSACTION类似于上面所说的BC_TRANSACTION,这里代表的是从服务端有数据发送过来,说明服务端主动传输数据。

所以这个时候就与service端建立了通信。

至此在client端的数据交互流程已经分析完毕,后续我们再来看binder传输过程中的service端,看它是如何接收与处理数据的。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-01-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android补给站 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • addService
  • startThreadPool
  • joinThreadPool
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档