Android’s Binder mechanism is simple

Android’s Binder mechanism is simple

A description

Binder is the most common Android operating system, and the most difficult for beginners to understand. Binder is the mechanism through which many services communicate with clients. So understanding Binder is a great way to understand the flow of your programs.

Binder is an example of MediaService:

L ServiceManager, which is the manager of the entire Android OS service

L MediaService, this program registers MediaPlayerService to provide media playback service, we will only analyze this

L MediaPlayerClient, this is the client program that interacts with MediaPlayerService

Let’s start with the MediaService application.

The birth of MediaService

MediaService is an application, and while Android makes all the JAVA stuff, it’s still a full Linux operating system at heart, and no applications are written in JAVA yet. So MS(MediaService) is the same thing as a normal C++ application.

The source file for MediaService is in: Framework \ Base \Media\ Mediaservermain_mediaserver.cpp. Let’s see what it is!

int main(int argc,char** argv)

{

// this is not a problem.

// Get an instance of ProcessState

sp<ProcessState>proc(ProcessState::self());

// Get a ServiceManager object

    sp<IServiceManager> sm =defaultServiceManager();

MediaPlayerService::instantiate(); // Initialize MediaPlayerService

ProcessState::self()->startThreadPool(); // Start the thread pool of Process.

IPCThreadState::self()->joinThreadPool(); // Add yourself to the thread pool.

}

Of these, we only analyze MediaPlayerService.

So many questions, it seems that we only have one function after another in-depth analysis. However, here is a brief introduction to sp.

Sp; smartPointer; strong pointer In fact, I later found that do not pay too much attention to this, put it as a common pointer, that is, SP <IServiceManager>====== IServiceManager*. Sp is Google came out in order to facilitate C/C++ programmers to manage pointer allocation and release of a set of methods, similar to what WeakReference JAVA. Personally, I think if you were writing your own program, you could do without it.

In future analysis, sp<XXX> can be regarded as XXX*.

2.1 ProcessState

The first function called is ProcessState::self(), which assigns a value to the proc variable. When the program runs, the Proc automatically deletes the internal contents, freeing the previously allocated resources.

The ProcessState location is framework\ Base \libs\binder\ processState.cpp

sp<ProcessState>ProcessState::self()

{

if (gProcess ! = NULL) return gProcess; —-> Definitely not here the first time you come in

AutoMutex _l(gProcessMutex); — – > lock protection

if (gProcess == NULL) gProcess = newProcessState; Create a ProcessState object

returngProcess; See, this returns a pointer, but the function returns sp< XXX >, so

// use sp< XXX > as XXX*

}

Look again at the ProcessState constructor

// This constructor looks important

ProcessState::ProcessState()

: mDriverFD(open_driver())—–>Android: mDriverFD(open_driver())—–>Android: mDriverFD(open_driver())—–>Android: mDriverFD(open_driver())—–>Android: mDriverFD(open_driver())—–

, mVMStart(MAP_FAILED)// Start address of mapped memory

    , mManagesContexts(false)

    , mBinderContextCheckFunc(NULL)

    , mBinderContextUserData(NULL)

    , mThreadPoolStarted(false)

    , mThreadPoolSeq(1)

{

if(mDriverFD >= 0) {

//BIDNER_VM_SIZE is defined as (1*1024*1024) – (4096 *2) 1m-8K

        mVMStart = mmap(0, BINDER_VM_SIZE,PROT_READ, MAP_PRIVATE | MAP_NORESERVE,

mDriverFD, 0); // This is a man mmap

// Map fd to memory, so that memory memcpy operations are equivalent to write/read(fd)

    }

.

}

I hate adding a function to the constructor list because I often forget that the initialization of a variable is the result of a function call.

Open_driver open_driver open_driver open_driver open_driver open_driver open_driver open_driver /dev/binder

A virtual device set up for interprocess communication. BTW is a mechanism provided by the kernel, and we use socket and NET_LINK to communicate with the kernel is the same reason.

static intopen_driver()

{

int fd = open(“/dev/binder”,O_RDWR); / / open/dev/binder

    if (fd >= 0) {

.

        size_t maxThreads = 15;

// Ioctl tells the kernel that the maximum number of threads supported by this fd is 15.

        result = ioctl(fd,BINDER_SET_MAX_THREADS, &maxThreads);   }

returnfd;

Okay, so that’s it for Process::self, so what did we do?

L Open the /dev/binder device so that it can interact with the kernel binder mechanism

L Maps FDS to memory, which is expected to be shared with binder devices after device FDS are passed in

 

Next, it’s time to call defaultServiceManager().

2.2 defaultServiceManager

DefaultServiceManager is located in Framework \ Base \libs\ Binder \ iservicemanager.cpp

sp<IServiceManager>defaultServiceManager()

{

if (gDefaultServiceManager ! = NULL) returngDefaultServiceManager;

// Another singleton, called singleton in the design pattern.

    {

        AutoMutex_l(gDefaultServiceManagerLock);

        if (gDefaultServiceManager == NULL) {

// The real gDefaultServiceManager is created here

            gDefaultServiceManager =interface_cast<IServiceManager>(

               ProcessState::self()->getContextObject(NULL));

        }

    }

   return gDefaultServiceManager;

}

— — — — –“

gDefaultServiceManager= interface_cast<IServiceManager>(

                ProcessState::self()->getContextObject(NULL));

ProcessState::self is sure to return the gProcess you just created, and then calls its getContextObject. Note that NULL, 0, is passed in

// Back to the ProcessState class,

sp<IBinder>ProcessState::getContextObject(const sp<IBinder>& caller)

{

If (supportsProcesses()) {// This function determines whether process is supported based on the success of opening the device,

// On a real plane, this is the way to go

return getStrongProxyForHandle(0); // Notice that 0 is passed in here

    }

}

—- goes to getStrongProxyForHandle, a function with a weird name that often severely hampers your brain

// Note the name of this parameter, handle. Those of you who have worked with Windows will be familiar with the name, that’s right

// An identifier for a resource, which is essentially a data structure stored in an array, and handle is its index in that array. –> It’s just such a thing

sp<IBinder>ProcessState::getStrongProxyForHandle(int32_t handle)

{

    sp<IBinder> result;

    AutoMutex _l(mLock);

handle_entry*e = lookupHandleLocked(handle); – “ha ha, sure enough, from the array to find the corresponding

The indexed resource, lookupHandleLocked, will return a handle_Entry internally

Here is the structure of handle_Entry

/ *

struct handle_entry {

IBinder* binder; —>Binder

RefBase::weakref_type* refs; –> If you don’t know what it is, it doesn’t matter.

            };

* /

if (e ! = NULL) {

IBinder* b = e->binder; –> < p style = “max-width: 100%; clear: both

if (b == NULL ||! e->refs->attemptIncWeak(this)) {

b = new BpBinder(handle); –> See, create a new BpBinder

            e->binder = b;

            result = b;

}…

    }

return result; Returns the BpBinder you just created.

}

// Is it a bit confusing here? Yes, it’s easy to forget when your brain is analyzing function calls too deeply.

GDefaultServiceManager = Interface_cast <IServiceManager>(

               ProcessState::self()->getContextObject(NULL));

Now, this function call is going to be

gDefaultServiceManager= interface_cast<IServiceManager>(new BpBinder(0));

What is BpBinder? Android has too many names.

Since the larger framework of Binder mechanism has not been introduced, it is not appropriate to introduce BpBinder here, but since we are talking about BpBinder, it seems that it is not clear without introducing Binder architecture…. , sigh!

Well, keep simplifying the deep function call stack, and at least your brain will still work. Let’s take a look at BpBinder’s constructor.

2.3 BpBinder

BpBinder location is in Framework \ Base \libs\binder\ bpbinder.cpp.

BpBinder::BpBinder(int32_thandle)

: mHandle(handle) // Note that 0 is passed in for this call

    , mAlive(1)

    , mObitsSent(0)

    , mObituaries(NULL)

{

IPCThreadState::self()->incWeakHandle(handle); // select * from IPCThreadState;

}

IPCThreadState::self is a singleton.

// The file is located in framework base libs binder ipcThreadState.cpp

IPCThreadState*IPCThreadState::self()

{

If (gHaveTLS) {// first entry is false

restart:

        const pthread_key_t k = gTLS;

//TLS is used for Thread Local Storage. All I need to do here is

// What is the advantage of knowing that there is one such space per thread and that threads do not share these Spaces? I don’t have to do anything

// It is synchronized. So in this thread, I’m just going to use this thread’s stuff, because no other thread can get the data in TLS from any other thread. === “this sentence has loopholes, it is ok to understand about the meaning of the point.

// Get the IPCThreadState object stored in thread local storage space

Pthread_getspecific = pthread_getSpecific = pthread_getSpecific = pthread_getSpecific

/ / pthread_setspecific.

        IPCThreadState* st =(IPCThreadState*)pthread_getspecific(k);

        if (st) return st;

return new IPCThreadState; // New object,

    }

   

    if(gShutdown) return NULL;

   

    pthread_mutex_lock(&gTLSMutex);

if (! gHaveTLS) {

if (pthread_key_create(&gTLS,threadDestructor) ! = 0) {

           pthread_mutex_unlock(&gTLSMutex);

            return NULL;

        }

        gHaveTLS = true;

    }

    pthread_mutex_unlock(&gTLSMutex);

gotorestart; // I FT, actually goto is not as vile as we said, assembly code many jump statements.

// The key is to use it well.

}

Pthread_setspecific (); pthread_setSpecific ()

IPCThreadState::IPCThreadState()

    : mProcess(ProcessState::self()),mMyThreadId(androidGetTid())

{

    pthread_setspecific(gTLS, this);

    clearCaller();

mIn.setDataCapacity(256);

//mIn,mOut is Parcel. Think of it as a buffer for commands. Any further explanation, and your brain will shut down again.

    mOut.setDataCapacity(256);

}

Come out, finally come out…. Well, back to BpBinder.

BpBinder::BpBinder(int32_thandle)

: mHandle(handle) // Note that 0 is passed in for this call

    , mAlive(1)

    , mObitsSent(0)

    , mObituaries(NULL)

{

.

IPCThreadState::self()->incWeakHandle(handle);

What incWeakHandle, do not talk about..

}

Oh, new BpBinder is done. So what have we created here?

L ProcessState is available.

L IPCThreadState is present and belongs to the main thread.

L BpBinder has an internal handle value of 0

 

gDefaultServiceManager =interface_cast<IServiceManager>(new BpBinder(0));

We’re back to square one. Are we losing our minds?

Interface_cast, which I first encountered as something like static_cast, and then couldn’t figure out how BpBinder* could be converted to IServiceManager*, Spent NTH more time checking whether BpBinder and IServiceManager inherit or what…. .

Finally, I use CTRL + mouse (Source Insight) to track into interface_cast

IInterface. H is located in the framework/base/include/binder/IInterface. H

template<typenameINTERFACE>

inlinesp<INTERFACE> interface_cast(const sp<IBinder>& obj)

{

    return INTERFACE::asInterface(obj);

}

Therefore, the above is equivalent to:

inline sp<IServiceManager>interface_cast(const sp<IBinder>& obj)

{

    return IServiceManager::asInterface(obj);

}

Looks like we have to follow IServiceManager.

IServiceManager. H – “framework/base/include/binder/IServiceManager. H

See how it is defined:

2.4 IServiceManager

classIServiceManager : public IInterface

{

// The ServiceManager manages what? Add services, query services, etc

// Only the addService function is listed here

public:

    DECLARE_META_INTERFACE(ServiceManager);

     virtual status_t   addService( const String16& name,

                                           const sp<IBinder>& service) = 0;

};

DECLARE_META_INTERFACE (ServiceManager)??

How is it so similar to MFC? Microsoft has a lot of influence! If you know MFC, DELCARE must have IMPLEMENT

And sure enough, the two macros, DECLARE_META_INTERFACE and IMPLEMENT_META_INTERFACE(INTERFACE, NAME), are there

I defined it in iinterface.h. What does the DECLARE_META_INTERFACE macro add to IServiceManager?

Here is the DECLARE macro

#defineDECLARE_META_INTERFACE(INTERFACE)                               \

    static const android::String16descriptor;                          \

    static android::sp<I##INTERFACE>asInterface(                       \

            constandroid::sp<android::IBinder>& obj);                  \

    virtual const android::String16&getInterfaceDescriptor() const;    \

    I##INTERFACE();                                                    \

    virtual ~I##INTERFACE();    

We cash it to IServiceManager is:

static constandroid::String16 descriptor; –> Oh, add a description string

staticandroid::sp< IServiceManager > asInterface(constandroid::sp<android::IBinder>&

Obj) — added an asInterface function

virtual constandroid::String16& getInterfaceDescriptor() const; Add a get function

The return value is supposed to be the string descriptor

IServiceManager();                                                    \

virtual ~IServiceManager(); Add construction and virtual decaying functions…

So where is this IMPLEMENT defined?

See IServiceManager. CPP. In the framework/base/libs/binder/IServiceManager CPP

IMPLEMENT_META_INTERFACE(ServiceManager,”android.os.IServiceManager”);

Here is the definition of this macro

#defineIMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \

    const android::String16I##INTERFACE::descriptor(NAME);            \

    const android::String16&                                            \

           I##INTERFACE::getInterfaceDescriptor() const {              \

        return I##INTERFACE::descriptor;                                \

    }                                                                  \

    android::sp<I##INTERFACE>I##INTERFACE::asInterface(               \

            constandroid::sp<android::IBinder>& obj)                   \

{\

        android::sp<I##INTERFACE>intr;                                 \

if (obj ! = NULL) { \

            intr =static_cast<I##INTERFACE*>(                          \

               obj->queryLocalInterface(                               \

                       I##INTERFACE::descriptor).get());               \

            if (intr == NULL) {                                         \

                intr = newBp##INTERFACE(obj);                         \

            }                                                           \

        }                                                              \

        return intr;                                                   \

    }                                                                  \

    I##INTERFACE::I##INTERFACE() { }                                    \

I##INTERFACE::~I##INTERFACE(){ }                                   \

Is it a hassle? Hiro, in particular, looks like he has a headache. Just cash it in.

const

Android: : String16IServiceManager: : descriptor (” android. OS. IServiceManager “);

constandroid::String16& IServiceManager::getInterfaceDescriptor() const

{ return IServiceManager::descriptor; / / return above the android OS. IServiceManager

   }                                                                     android::sp<IServiceManager> IServiceManager::asInterface(

            constandroid::sp<android::IBinder>& obj)

    {

        android::sp<IServiceManager>intr;

if (obj ! = NULL) {

            intr = static_cast<IServiceManager*>(                         

                obj->queryLocalInterface(IServiceManager::descriptor).get());              

            if (intr == NULL) {                                         

                intr = new BpServiceManager(obj);                         

            }                                                          

        }                                                              

        return intr;                                                   

    }                                                                 

    IServiceManager::IServiceManager () {}                                   

    IServiceManager::~ IServiceManager() { }

Interface_cast BpBinder/IServiceManager

Interface_cast > IServiceManager (new BpBinder(0))

AsInterface (New BpBinder(0))

android::sp<IServiceManager>IServiceManager::asInterface(

            constandroid::sp<android::IBinder>& obj)

    {

        android::sp<IServiceManager>intr;

if (obj ! = NULL) {

.

                intr = new BpServiceManager(obj);

// God, finally see something related to IServiceManager, look

BpServiceManager(new BpBinder(0));

            }                                                          

        }                                                              

        return intr;                                                   

}                                

What the hell is BpServiceManager? What does p stand for?

2.5 BpServiceManager

Finally, we can talk about architecture. P is proxy, Bp is BinderProxy, BpServiceManager is THE Binder agent of SM. Since it is a proxy, it must want to be transparent to the user, that is, there is no definition of Bp in the header file. Isn’t it?

Sure enough, BpServiceManager was just defined in iservicemanager.cpp.

classBpServiceManager : public BpInterface<IServiceManager>

// This type of inheritance means that both BpInterface and IServiceManager are inherited, so IServiceManger

AddService must be implemented in this class

{

public:

// Note the impl name of the constructor argument. Is Bridge mode used? Is the IMPL object really done?

Impl newBpBinder(0)

    BpServiceManager(constsp<IBinder>& impl)

        :BpInterface<IServiceManager>(impl)

    {

    }

     virtual status_t addService(constString16& name, const sp<IBinder>& service)

    {

More on that later..

}

Constructor of base class BpInterface (after cashed)

// The remote parameter is remote.

inlineBpInterface< IServiceManager >::BpInterface(const sp<IBinder>&remote)

    : BpRefBase(remote)

{

}

BpRefBase::BpRefBase(constsp<IBinder>& o)

    : mRemote(o.get()), mRefs(NULL), mState(0)

//o.get(), this is a method of the sp class to get the actual data pointer, just know

// it returns a pointer to sp< XXXX >

{

//mRemote is BpBinder(0)

.

}

Ok, so here we are:

sp<IServiceManager> sm =defaultServiceManager(); The actual return is BpServiceManager, whose remote object is BpBinder, and the handle argument passed in is 0.

Now back to MediaService.

int main(int argc,char** argv)

{

    sp<ProcessState>proc(ProcessState::self());

sp<IServiceManager>sm = defaultServiceManager();

// That’s it

MediaPlayerService::instantiate(); // Instantiate MediaPlayerservice

// There is something going on here!

 

    ProcessState::self()->startThreadPool();

    IPCThreadState::self()->joinThreadPool();

}

At this point, we turn on the Binder device and get a BpServiceManager object, which means we can deal with SM, but we’re not doing anything meaningful, are we?

2.6 MediaPlayerService

So what do we do next? Take MediaPlayerService as an example.

It is located in the framework/base/media/libmediaplayerservice \ libmediaplayerservice CPP

voidMediaPlayerService::instantiate() {

defaultServiceManager()->addService(

// Pass in the name of the service, pass in the object out of new

            String16(“media.player”),new MediaPlayerService());

}

MediaPlayerService::MediaPlayerService()

{

LOGV(“MediaPlayerServicecreated”); // Too simple

    mNextConnId = 1;

}

DefaultServiceManager returns the BpServiceManager you just created

Call its addService function.

MediaPlayerService is derived from BnMediaPlayerService

classMediaPlayerService : public BnMediaPlayerService

FT MediaPlayerService derived from BnMediaPlayerService BnXXX BpXXX

Bn is the meaning of Binder Native, as opposed to Bp, and THE P of Bp means proxy. Then there must be something on the other end that deals with proxy, and this is Bn.

This is going to be a little confusing. Let’s analyze what we’ve constructed so far.

l        BpServiceManager

l        BnMediaPlayerService

The two objects are not at opposite ends. From BnXXX, it can be inferred that BpServiceManager corresponds to BnServiceManager, and BnMediaPlayerService corresponds to BpMediaPlayerService.

Where are we now? We have now created the BnMediaPlayerService and want to add it to the system.

Oh, I see. I create a new service-bnMediaPlayerService-and want to tell it to the ServiceManager.

So how do I communicate with the ServiceManager? Well, use BpServiceManager. So, I called BpServiceManager addService!

Why have a ServiceManager? This has to do with Android mechanics. All services must be added to the ServiceManager to manage them. It also makes it easier for the Client to check which services exist in the system. Didn’t you see the string we passed in? This makes it possible to find the Service using the Human Readable string.

I don’t feel clear… Forgive me.

2.7 the addService

AddService is the function called BpServiceManager. I didn’t get to that, but now let’s see.

virtual status_taddService(const String16& name, const sp<IBinder>& service)

    {

        Parcel data, reply;

// Data is the command package sent to BnServiceManager

// See? First written into, the Interface name. What is the android OS. IServiceManager

       data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());

// Add the name of the new service called media.player

        data.writeString16(name);

// Write the new service service — > MediaPlayerService to the command

        data.writeStrongBinder(service);

// Call remote’s transact function

        status_t err =remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

return err == NO_ERROR ? reply.readInt32() : err;

}

Omg, what does remote() return?

remote(){ return mRemote; } — >? Can not find the corresponding actual object?

Remember what we said when we initialized:

This parameter is also called remote.

MRemote was originally created as BpBinder..

Well, go there and check it out:

The location of BpBinder is framework\base\libs\binder\ bpbinder.cpp

status_tBpBinder::transact(

    uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)

{

// Call transact of IPCThreadState.

// mHandle is 0,code is ADD_SERVICE_TRANSACTION, and data is the command package

// Reply is the reply package, flags=0

        status_t status =IPCThreadState::self()->transact(

            mHandle, code, data, reply, flags);

        if (status == DEAD_OBJECT) mAlive = 0;

        return status;

    }

.

}

Take a look at the transact function for IPCThreadState

status_tIPCThreadState::transact(int32_t handle,

                                  uint32_tcode, const Parcel& data,

                                  Parcel* reply,uint32_t flags)

{

    status_t err = data.errorCheck();

 

    flags |= TF_ACCEPT_FDS;

   

    if (err == NO_ERROR) {

// Call writeTransactionData to send data

err = writeTransactionData(BC_TRANSACTION, flags,handle, code, data, NULL);

    }

   

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

        if (reply) {

            err = waitForResponse(reply);

        } else {

            Parcel fakeReply;

            err =waitForResponse(&fakeReply);

        }

. Reply etc.

        err = waitForResponse(NULL, NULL);

.

    return err;

}

Take it one step further and look at this…

status_tIPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,

    int32_t handle, uint32_t code, constParcel& data, status_t* statusBuffer)

{

    binder_transaction_data tr;

 

    tr.target.handle = handle;

    tr.code = code;

    tr.flags = binderFlags;

   

    const status_t err = data.errorCheck();

    if (err == NO_ERROR) {

        tr.data_size = data.ipcDataSize();

        tr.data.ptr.buffer = data.ipcData();

        tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);

        tr.data.ptr.offsets =data.ipcObjects();

    }

.

The command data is encapsulated as binder_transaction_data, and then

Write to mOut, which is a command buffer and Parcel

    mOut.writeInt32(cmd);

    mOut.write(&tr, sizeof(tr));

// Add Parcel to /dev/binder.

Well, that has to be written to binder devices in another place. Is it in?

    return NO_ERROR;

}

// Yes, in waitForResponse

status_tIPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)

{

    int32_t cmd;

    int32_t err;

 

while(1) {

//talkWithDriver, ha ha, should be here

        if ((err=talkWithDriver()) <NO_ERROR) break;

        err = mIn.errorCheck();

        if (err < NO_ERROR) break;

        if (mIn.dataAvail() == 0) continue;

// See? So here I’m doing mIn, so it looks like in talkWithDriver

// Send out the mOut and read the data from the driver into mIn.

        cmd = mIn.readInt32();

 

        switch (cmd) {

        caseBR_TRANSACTION_COMPLETE:

if (! reply &&! acquireResult) goto finish;

            break;

.

    return err;

}

status_tIPCThreadState::talkWithDriver(bool doReceive)

{

binder_write_read bwr;

// mOut data and mIn received data are assigned to BWR.

    status_t err;

    do {

// Use ioctl to read and write

        if (ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr) >= 0)

            err = NO_ERROR;

        else

            err = -errno;

  } while (err == -EINTR);

// At this point, the reply data is in the BWR, and the buffer that BMR receives the reply data is provided by mIn

        if (bwr.read_consumed > 0) {

            mIn.setDataSize(bwr.read_consumed);

            mIn.setDataPosition(0);

        }

returnNO_ERROR;

}

Well, at this point, we’re done sending addService.

BpServiceManager sends an addService command to BnServiceManager and receives a reply.

Let’s continue with our main function.

int main(int argc,char** argv)

{

    sp<ProcessState>proc(ProcessState::self());

    sp<IServiceManager> sm =defaultServiceManager();   

MediaPlayerService::instantiate();

This function internally calls addService to add MediaPlayerService information to the ServiceManager

    ProcessState::self()->startThreadPool();

   IPCThreadState::self()->joinThreadPool();

}

Here’s where it’s easy to get confused:

MediaPlayerService is a BnMediaPlayerService, so it should not wait

BpMediaPlayerService to interact with him? We don’t see MediaPlayerService opening binder devices.

BnServiceManager will continue with addService

BnMediaPlayerService?

Let’s start with BnServiceManager. By the way, the Binder architecture of the system.

2.8 BnServiceManager

As mentioned above, defaultServiceManager returns a BpServiceManager through which command requests can be sent to binder devices and handle has a value of 0. Well, there must be someone on the other end of the system receiving orders. Who is that?

Unfortunately, BnServiceManager does not exist, but there is a program that does BnServiceManager’s job: service.exe. Exe means it’s a program.

Location in the framework/base/CMDS servicemanger. C.

int main(int argc,char **argv)

{

    struct binder_state *bs;

    void *svcmgr = BINDER_SERVICE_MANAGER;

bs = binder_open(128*1024); // Open binder devices.

Binder_become_context_manager (bs) // Become manager

    svcmgr_handle = svcmgr;

binder_loop(bs, svcmgr_handler); // Process the command sent by BpServiceManager

}

See if binder_open is as good as we guessed?

struct binder_state*binder_open(unsigned mapsize)

{

    struct binder_state *bs;

    bs = malloc(sizeof(*bs));

.

bs->fd = open(“/dev/binder”,O_RDWR); // Sure enough

.

    bs->mapsize = mapsize;

    bs->mapped = mmap(NULL, mapsize,PROT_READ, MAP_PRIVATE, bs->fd, 0);

  }

Look again at binder_become_context_manager

intbinder_become_context_manager(struct binder_state *bs)

{

return ioctl(bs->fd,BINDER_SET_CONTEXT_MGR, 0); // Set yourself to MANAGER

}

Binder_loop must be a loop that reads requests and writes replies from binder devices, right?

voidbinder_loop(struct binder_state *bs, binder_handler func)

{

    int res;

    struct binder_write_read bwr;

    readbuf[0] = BC_ENTER_LOOPER;

    binder_write(bs, readbuf,sizeof(unsigned));

for (;;) {// It’s a loop

        bwr.read_size = sizeof(readbuf);

        bwr.read_consumed = 0;

        bwr.read_buffer = (unsigned) readbuf;

 

       res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

// I received the request

        res = binder_parse(bs, 0, readbuf,bwr.read_consumed, func);

  }

This… More to say later?

Well, finally, there’s a handleMessage-like place to handle all kinds of commands. This is the

Svcmgr_handler, which is in Servicemanager.c

intsvcmgr_handler(struct binder_state *bs,

                   struct binder_txn *txn,

                   struct binder_io *msg,

                   struct binder_io *reply)

{

    struct svcinfo *si;

    uint16_t *s;

    unsigned len;

    void *ptr;

 

    s = bio_get_string16(msg, &len);

    switch(txn->code) {

    case SVC_MGR_ADD_SERVICE:

        s = bio_get_string16(msg, &len);

        ptr = bio_get_ref(msg);

        if (do_add_service(bs, s, len, ptr,txn->sender_euid))

            return -1;

        break;

.

Where do_add_service actually adds BnMediaService information

intdo_add_service(struct binder_state *bs,

                   uint16_t *s, unsigned len,

                   void *ptr, unsigned uid)

{

    struct svcinfo *si;

si = find_svc(s, len); S is a list

     si = malloc(sizeof(*si) + (len + 1) *sizeof(uint16_t));

       si->ptr = ptr;

        si->len = len;

        memcpy(si->name, s, (len + 1) *sizeof(uint16_t));

        si->name[len] = ‘\0’;

        si->death.func = svcinfo_death;

        si->death.ptr = si;

        si->next = svclist;

svclist = si; // See, the svclist is a list that holds the current registration to the ServiceManager

The information in the

    }

binder_acquire(bs, ptr); // This one. When this Service exits, I want the system to notify me so that I can release resources from malloc. That’s probably what they do.

    binder_link_to_death(bs, ptr,&si->death);

    return 0;

}

Well, as far as addService is concerned, it looks like the ServiceManager adds the information to a list of services it maintains.

2.9 Significance of the ServiceManager

Why do you need something like this?

In Android, the Service information is added to the ServiceManager. The ServiceManager manages the Service information in a centralized manner. In this way, you can query the services available in the system. If a client of an Android service such as MediaPlayerService wants to communicate with MediaPlayerService, it must first query the MediaPlayerService with the ServiceManager. The ServiceManager then interacts with the MediaPlayerService through what it returns.

After all, if the MediaPlayerService is in bad health and keeps failing, the client code will be in trouble and will not know about the subsequent new MediaPlayerService, so this is what happens:

L MediaPlayerService registers with SM

L MediaPlayerClient Queries information about the MediaPlayerService currently registered in SM

L Based on this information, MediaPlayerClient interacts with MediaPlayerService

In addition, the Handle identifier of the ServiceManager is 0, so any message sent to a service with a Handle of 0 will eventually be passed to the ServiceManager.

The operation of MediaService

In the last section, we learned:

L defaultServiceManager gets BpServiceManager, then MediaPlayerService instantiates and calls BpServiceManager’s addService function

In this process, it is the Service_manager that receives the addService request and puts the corresponding information into its own service list

Here, we can see that service_manager has a binder_looper function waiting to receive requests from binder. Although Service_manager is not derived from BnServiceManager, it certainly does what BnServiceManager does.

Similarly, we created MediaPlayerService (BnMediaPlayerService), which should also:

L Open binder equipment

Do a Looper loop, too, and wait for the request

Service, service, this is similar to network programming to listen to socket work.

Well, since the MediaPlayerService constructor doesn’t see the binder device being opened, what does its parent, BnXXX, do?

3.1 MediaPlayerService Enable Binder

classMediaPlayerService : public BnMediaPlayerService

//MediaPlayerService is derived from BnMediaPlayerService

BnMediaPlayerService is derived from both BnInterface and IMediaPlayerService

classBnMediaPlayerService: public BnInterface<IMediaPlayerService>

{

public:

    virtual status_t    onTransact( uint32_t code,

                                    constParcel& data,

                                    Parcel*reply,

                                    uint32_t flags= 0);

};

BnInterface seems to be more about opening devices.

template<typenameINTERFACE>

class BnInterface :public INTERFACE, public BBinder

{

public:

    virtual sp<IInterface>      queryLocalInterface(const String16&_descriptor);

    virtual const String16&     getInterfaceDescriptor() const;

 

protected:

    virtual IBinder*            onAsBinder();

};

Cashed into

class BnInterface :public IMediaPlayerService, public BBinder

BBinder? BpBinder? BnXXX = BnXXX = BpXXX If so, why is it called BBinder?

BBinder::BBinder()

    : mExtras(NULL)

{

// Where is the device not turned on?

}

Finished? Are we going in the wrong direction? Doesn’t every Service have a corresponding BINDER device FD?

.

Think back to our Main_MediaService app. Did any of binder open?

int main(int argc,char** argv)

{

// don’t I have binder open in ProcessState?

 

    sp<ProcessState> proc(ProcessState::self());

    sp<IServiceManager> sm =defaultServiceManager();

MediaPlayerService::instantiate();   

.

3.2 which

Ah? The opening of binder devices is process related. Open one for each process. So where do I do a similar message loop looper operation?

.

// Is it the following two?

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

Have a look at startThreadPool

voidProcessState::startThreadPool()

{

.

    spawnPooledThread(true);

}

voidProcessState::spawnPooledThread(bool isMain)

{

sp<Thread> t = newPoolThread(isMain); IsMain is TRUE

// Create a Thread pool and run it.

    t->run(buf);

 }

PoolThread is derived from the Thread class, so is a Thread generated at this point? Take a look at PoolThread and Thread construction

PoolThread::PoolThread(boolisMain)

        : mIsMain(isMain)

    {

    }

Thread::Thread(boolcanCallJava)//canCallJava Default value is true

    :  mCanCallJava(canCallJava),

        mThread(thread_id_t(-1)),

        mLock(“Thread::mLock”),

        mStatus(NO_ERROR),

        mExitPending(false), mRunning(false)

{

}

Oh, no thread has been created yet. PoolThread::run is then called, actually calling the run of the base class.

status_tThread::run(const char* name, int32_t priority, size_t stack)

{

  bool res;

    if (mCanCallJava) {

Res = createThreadEtc(_threadLoop,// thread function is _threadLoop

                this, name, priority, stack,&mThread);

    }

// Finally, in the run function, the thread is created. From now on

Main thread execution

IPCThreadState::self()->joinThreadPool();

The newly opened thread executes _threadLoop

Let’s look at _threadLoop first

intThread::_threadLoop(void* user)

{

    Thread* const self =static_cast<Thread*>(user);

    sp<Thread>strong(self->mHoldSelf);

    wp<Thread> weak(strong);

    self->mHoldSelf.clear();

 

    do {

.

if (result && ! self->mExitPending){

result = self->threadLoop(); Wow, call your own threadLoop

            }

        }

We are PoolThread objects, so call the PoolThread threadLoop function

virtualbool PoolThread ::threadLoop()

    {

/ / mIsMain to true.

// Also note that this is a new thread, so one must be created

The new IPCThreadState object (remember thread-local storage? TLS) and then

IPCThreadState::self()->joinThreadPool(mIsMain);

        return false;

    }

Both the main thread and the worker thread called joinThreadPool.

voidIPCThreadState::joinThreadPool(bool isMain)

{

     mOut.writeInt32(isMain ? BC_ENTER_LOOPER :BC_REGISTER_LOOPER);

     status_t result;

    do {

        int32_t cmd;

         result = talkWithDriver();

         result = executeCommand(cmd);

        }

} while (result ! = -ECONNREFUSED&& result ! = -EBADF);

 

    mOut.writeInt32(BC_EXIT_LOOPER);

    talkWithDriver(false);

}

See yet? There is a loop, but it looks like two threads are executing it! There are two message loops, right?

Now look at executeCommand

status_tIPCThreadState::executeCommand(int32_t cmd)

{

BBinder*obj;

    RefBase::weakref_type* refs;

    status_t result = NO_ERROR;

caseBR_TRANSACTION:

        {

            binder_transaction_data tr;

            result = mIn.read(&tr,sizeof(tr));

// a command comes in, parses into BR_TRANSACTION, and reads the subsequent information

       Parcel reply;

             if (tr.target.ptr) {

// Use BBinder.

                sp<BBinder>b((BBinder*)tr.cookie);

                const status_t error =b->transact(tr.code, buffer, &reply, 0);

}

Let’s see what BBinder’s transact function does

status_tBBinder::transact(

    uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)

{

Call your own onTransact function

err= onTransact(code, data, reply, flags);

    return err;

}

BnMediaPlayerService is derived from BBinder, so its onTransact function is called

Finally, let’s look at BnMediaPlayerServcice’s onTransact function.

status_tBnMediaPlayerService::onTransact(

    uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)

{

BnMediaPlayerService is derived from BBinder and IMediaPlayerService, all iMediaPlayerServices

// See the switch below? All functions provided by IMediaPlayerService are distinguished by command types

//

    switch(code) {

        case CREATE_URL: {

           CHECK_INTERFACE(IMediaPlayerService, data, reply);

Create is a virtual function implemented by MediaPlayerService!!

sp<IMediaPlayer> player = create(

                    pid, client, url,numHeaders > 0 ? &headers : NULL);

 

           reply->writeStrongBinder(player->asBinder());

            return NO_ERROR;

        } break;

In fact, at this point, we understand. The onTransact function of BnXXX takes the command and sends it to the functions of derived classes, who do the actual work.

Description:

There are two threads, the main thread and the worker thread, after startThreadPool and joinThreadPool are done, and both are doing message loops. Why do you do that? They both take isMain to be true. I don’t know what Google is doing. Are you afraid that one thread is too much work, so you have two threads to work on? This explanation should also be reasonable.

Someone on the Internet has tested that the last sentence is blocked, and it works. But if the main thread is raised, can the program not exit? This… Whatever, just know that there are two threads working on it.

Four MediaPlayerClient

This is how the MediaPlayerClient interacts with the MediaPlayerService.

To use MediaPlayerService, create its BpMediaPlayerService. Let’s look at an example

IMediaDeathNotifier::getMediaPlayerService()

{

        sp<IServiceManager> sm =defaultServiceManager();

        sp<IBinder> binder;

        do {

// Query SM for service information, return binder

binder =sm->getService(String16(“media.player”));

if (binder ! = 0) {

                break;

             }

usleep(500000); / / 0.5 s

        } while(true);

 

// Convert this binder to BpMediaPlayerService via interface_cast

// Note that binder is only used to communicate with binder devices

// has nothing to do with the functionality of IMediaPlayerService.

// Remember what I said about Bridge mode? BpMediaPlayerService uses this binder and BnMediaPlayerService

/ / communications.

    sMediaPlayerService =interface_cast<IMediaPlayerService>(binder);

    }

    return sMediaPlayerService;

}

Why the Bridge? It’s not necessarily Bridge mode, but what I really want to say is:

A Binder is simply an interface to a Binder device, and the upper-layer IMediaPlayerService uses it as a socket. I used to confuse binder with the functionality of the upper class IMediaPlayerService.

Of course, you don’t have to make that mistake. But there is one caveat:

4.1 Native layer

The getMediaPlayerService code is C++ layer, but the entire example used is a JAVA->JNI layer call. What if I wanted to write a pure C++ program?

int main()

{

getMediaPlayerService(); Can I get BpMediaPlayerService by calling this function directly?

No, why not? Because I haven’t turned on the Binder drive yet! But you have Google already doing it for you in your JAVA application

It’s packaged.

Therefore, pure native layer code must also be treated like this:

sp<ProcessState>proc(ProcessState::self()); // This is not necessary because

// This is required in many places, so it will be created automatically.

getMediaPlayerService();

You have to have a message loop, otherwise if there is a message from Bn, how can you receive it?

ProcessState::self()->startThreadPool();

// Whether the main thread also calls the message loop depends on the individual. Instead, you wait to receive messages from other sources, such as socket commands, and then control MediaPlayerService.

}

 

Implement your own Service

With binders, how do you implement your own Service?

If it were a pure C++ program, it would have to act like main_MediaService.

int main()

{

  sp<ProcessState>proc(ProcessState::self());

sp<IServiceManager>sm = defaultServiceManager();

Sm – > the addService (” service. The name “newXXXService ());

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

}

How to define XXXService?

We need a Bn, we need a Bp, and the Bp doesn’t have to be exposed. So implement it together in bnxxx.cpp.

In addition, XXXService provides its own functionality, such as getXXX calls

5.1 Defining the XXX Interface

The XXX interface is related to the XXX service, such as providing getXXX, setXXX functions, and application logic.

Needs to be derived from IInterface

class IXXX: publicIInterface

{

public:

DECLARE_META_INTERFACE(XXX); ShenMingHong

virtualgetXXX() = 0;

virtualsetXXX() = 0;

} This is an interface.

5.2 Define BnXXX and BpXXX

To add IXXX to the Binder structure, you need to define BnXXX and CLIENT-transparent BpXXX.

BnXXX requires a header file. BnXXX simply adds the IXXX interface to the Binder architecture without participating in the actual getXXX and setXXX application-layer logic.

This BnXXX definition can be placed alongside the IXXX definition above. We can split up.

class BnXXX: publicBnInterface<IXXX>

{

public:

    virtual status_t    onTransact( uint32_t code,

                                    constParcel& data,

                                    Parcel*reply,

                                    uint32_tflags = 0);

// since IXXX is a pure virtual class, BnXXX implements only onTransact, so BnXXX is still a virtual class

A pure virtual class

};

So, given DECLARE, let’s IMPLEMNT it in a CPP. In ixxx. CPP.

IMPLEMENT_META_INTERFACE(XXX,”android.xxx.IXXX”); / / IMPLEMENT macro

 

status_t BnXXX::onTransact(

    uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)

{

    switch(code) {

        case GET_XXX: {

            CHECK_INTERFACE(IXXX, data, reply);

Read request parameters

Call the virtual function getXXX()

            return NO_ERROR;

} break; / / SET_XXX similar

BpXXX is also implemented here.

class BpXXX: publicBpInterface<IXXX>

{

public:

    BpXXX(const sp<IBinder>& impl)

        : BpInterface< IXXX >(impl)

    {

}

vituralgetXXX()

{

  Parcel data, reply;

  data.writeInterfaceToken(IXXX::getInterfaceDescriptor());

   data.writeInt32(pid);

   remote()->transact(GET_XXX, data,&reply);

   return;

}

/ / setXXX similar

At this point, Binder should be able to do the following after the analysis:

If you need to write your own Service, you should always know how the system calls your function. right There are two threads out there constantly taking commands from binder devices and calling your functions. Well, this is a multithreading problem.

If you need to track bugs, you need to know how functions called from the Client end up in the remote Service. Thus, for some function calls, when the Client is done tracing, I know to go to Service to see the corresponding function call. It’s synchronous anyway. The Client waits for a function call until the Service returns.