This article was published on the public account: Android supply website, focusing on Android progression, algorithm and interview analysis.

In the Binder: ServiceManager acquisition article, the ProcessState and IPCThreadState creation are analyzed. Finally, in defaultServiceManager, the BpServiceManager object holding BpBinder is returned.

 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());
  }
Copy the code

So the addService called in the Instantiate method is actually the BpServiceManager method that registers the MediaPlayerService object named Media.Player

addService

Let’s look directly at addService in BpServiceManager.

virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated, Int dumpsysPriority) {// Encapsulate to Parcel object 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; }Copy the code

The data is encapsulated into a Parcel object and finally transferred to the remote using remote() ‘s transact method with the code ADD_SERVICE_TRANSACTION.

Now let’s take a look at what remote() really is.

It is a method in BpServiceManager that comes from its parent class

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;
};
Copy the code

Inheriting from the process above, the remote() returns mRemote, which is the original parameter BpBinder(0). The transact method of BpBinder is called

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;
}
Copy the code

Enter BpBinder and find transact methods that switch to IPCThreadState

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; }Copy the code

There are two main things to do here

  1. throughwriteTransactionDataWrite data toParcel, corresponding tocmdCommand toBC_TRANSACTION, this is the request code, the corresponding isBC_Name it at the beginningserviceThe end will use these request codes to do different logic processing.
  2. throughwaitForResponseTo wait for the data to return from the remote side, and there’s one here as wellcmdCommand line, for exampleBR_REPLY, this is the return code, the corresponding isBR_It’s named at the beginning, inclientIt also uses these return codes to do different logic processing.

We won’t look at these methods today; future articles will focus on data interaction.

Now that MediaPlayerService is registered, let’s take the main method and go down.

startThreadPool

ProcessState::self()->startThreadPool();
Copy the code

Again, the method in ProcessState, go to startThreadPooll and see.

void ProcessState::startThreadPool() { AutoMutex _l(mLock); if (! mThreadPoolStarted) { mThreadPoolStarted = true; spawnPooledThread(true); } } void ProcessState::spawnPooledThread(bool isMain) { if (mThreadPoolStarted) { String8 name = makeBinderThreadName();  Sp <Thread> t = new PoolThread(isMain); t->run(name.string()); }}Copy the code

The PoolThread pool is created in the spawnPooledThread method, which inherits from Thread and finally calls the run method of the Thread

joinThreadPool

IPCThreadState::self()->joinThreadPool();
Copy the code

Moving on to the joinThreadPooll method, which is in IPCThreadState

void IPCThreadState::joinThreadPool(bool isMain) { mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); status_t result; do { processPendingDerefs(); // Waiting for the command line result = getAndExecuteCommand(); } while (result ! = -ECONNREFUSED && result ! = -EBADF); mOut.writeInt32(BC_EXIT_LOOPER); // Communicate with binder driver talkWithDriver(false); }Copy the code

The main method here is getAndExecuteCommand(), which is used to process data from the receiving service, since the service and client can initiate data interaction with each other. In this case, the client acts as a service. It starts polling and listens for the data sent by the service. Eventually it calls executeCommand to unify the processing.

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) {// Send a reply to the server. 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; }Copy the code

To simplify the code and show only the main parts of the code, BR_TRANSACTION is similar to BC_TRANSACTION, where data is sent from the server, indicating that the server actively transfers data.

Therefore, the communication with the server is established.

So far, the data interaction process on the client side has been analyzed. Subsequently, we will look at the service side in the transmission process of binder to see how it receives and processes data.

recommended

Android_startup: Provides a simpler and more efficient way to initialize components at application startup. Developers can use Android-startup to simplify the startup sequence and explicitly set the dependency between the initialization order and the components. Meanwhile, Android-startup supports synchronous and asynchronous wait, and ensures the initialization sequence of internal dependent components by means of directed acyclic topology sorting.

AwesomeGithub: Based on Github client, pure exercise project, support componentized development, support account password and authentication login. Kotlin language for development, the project architecture is based on Jetpack&DataBinding MVVM; Popular open source technologies such as Arouter, Retrofit, Coroutine, Glide, Dagger and Hilt are used in the project.

Flutter_github: a cross-platform Github client based on Flutter, corresponding to AwesomeGithub.

Android-api-analysis: A comprehensive analysis of Knowledge points related to Android with detailed Demo to help readers quickly grasp and understand the main points explained.

Daily_algorithm: advanced algorithm, from shallow to deep, welcome to join us.