Android backstage Kill (four): Binder obituary principle

Binder is similar to C / communication framework S framework, sometimes clients may want to know the status of the server, such as server if hung up, the client wants to be able to timely be notified, rather than wait until the renewed request to the server side only know, this scenario is actually the most commonly used at the time of each other C / S, such as AMS and APP, APP when abnormal exit end of the process, AMS hope to know in time, not just clean up some of the information in the AMS end of APP, For example ActivityRecord, ServiceRecord, etc., and sometimes may also need time to restore some self-initiated Service. Binder achieve a set of "obituary" function, namely: the server hung up, or normal exit, Binder driver will send a copy of the obituary to the client, tell the client service Binder hung up.

This "obituary" exactly how to achieve it? What its role is it? For the purposes of Android, Binder "obituary" somewhat adopted a similar observer mode, you first need to register Observer to the target object, in fact, registered to the Client drive Binder, Binder future service hang time, you can go through the drive send. Entrance Binder "obituary" send only one: when releasing binder equipment , was recovered in the operating system, whether the process is a normal exit or quit unexpectedly, the process of the application of all resources will be, including opening some device files, such as Binder character equipment. When released, it will call the appropriate release function, "obituary" is, at this time to send. So Binder obituary in fact only consists of two parts: registration and notification.

Binder "obituary" of registered importers

Take as an example here bindService were analyzed, similar to other scenes, bindService will first request to start the AMS Service, Server-side process at startup, it will call the function open to open the device file / dev / binder, while Binder service entities back to AMS , then Binder AMS reference entity handle is passed to the Client by Binder communication, that is, back to the AMS Client, when registration will be driven to the Binder. In fact, this is better understood, access to the proxy server, you should be concerned about end of service life and death . When using the AMS IServiceConnection time this binder communication lines to return Binder Client service entity, InnerConnection will indirectly to the deaths registered callback kernel:

    private static class InnerConnection extends IServiceConnection.Stub {
        final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

        public void connected(ComponentName name, IBinder service) throws RemoteException {
            LoadedApk.ServiceDispatcher sd = mDispatcher.get();
            if (sd != null) {
                sd.connected(name, service);
            }
        }
    }

ServiceDispatcher function further calls doConnected

public void doConnected(ComponentName name, IBinder service) {
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;
    synchronized (this) {     
        if (service != null) {
            mDied = false;
            info = new ConnectionInfo();
            info.binder = service;
            info.deathMonitor = new DeathMonitor(name, service);
            try {
            <!-- 关键点点1-->
                service.linkToDeath(info.deathMonitor, 0);
            } 
}

1 key little look, here IBinder service is actually AMS backhaul service agent BinderProxy, linkToDeath is a Native function, further calls BpBinde of linkToDeath:

status_t BpBinder::linkToDeath(
    const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags){
    <!--关键点1-->              
                IPCThreadState* self = IPCThreadState::self();
                self->requestDeathNotification(mHandle, this);
                self->flushCommands();

}

The final call IPCThreadState of requestDeathNotification (mHandle, this) BC_REQUEST_DEATH_NOTIFICATION send a request to the kernel:

status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{
    mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
    mOut.writeInt32((int32_t)handle);
    mOut.writeInt32((int32_t)proxy);
    return NO_ERROR;
}

Finally, look in the kernel, it is how registered:

int
binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
            void __user *buffer, int size, signed long *consumed)
{
...
case BC_REQUEST_DEATH_NOTIFICATION:
        case BC_CLEAR_DEATH_NOTIFICATION: {
            ...
            ref = binder_get_ref(proc, target);
            if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
                ...关键点1
                death = kzalloc(sizeof(*death), GFP_KERNEL);
                binder_stats.obj_created[BINDER_STAT_DEATH]++;
                INIT_LIST_HEAD(&death->work.entry);
                death->cookie = cookie;
                ref->death = death;
                if (ref->node->proc == NULL) {
                    ref->death->work.type = BINDER_WORK_DEAD_BINDER;
                    if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
                        list_add_tail(&ref->death->work.entry, &thread->todo);
                    } else {
                        list_add_tail(&ref->death->work.entry, &proc->todo);
                        wake_up_interruptible(&proc->wait);
                    }
                }
            } 
 }

Critical Points 1, in fact, is the new Client binder_ref_death objects, and assigned to binder_ref. In the binder driver, binder_node node will record all binder_ref , when the process binder_node where the hang up, drivers will be able to find all Client of binder_ref according to this global binder_ref list, and to set up a callback death of Client sends a "obituary", which is because binder_get_ref_for_node insert binder_ref to the Client it will also insert binder_node of binder_ref list.

static struct binder_ref *
binder_get_ref_for_node(struct binder_proc *proc, struct binder_node *node)
{
    struct rb_node *n;
    struct rb_node **p = &proc->refs_by_node.rb_node;
    struct rb_node *parent = NULL;
    struct binder_ref *ref, *new_ref;

    if (node) {
        hlist_add_head(&new_ref->node_entry, &node->refs);
        }
    return new_ref;
}

So, death was registered callback entrance to the binder kernel driver, then, until the end of the process to release the binder when death will trigger a callback.

Send notification of death

When calling binder_realease function to release the appropriate resources, eventually calls binder_deferred_release function. This function will traverse all nodes in the binder_node binder_proc, and registered with the Client's death callback send obituary,

static void binder_deferred_release(struct binder_proc *proc)
    {         ....
        if (ref->death) {
                death++;
                if (list_empty(&ref->death->work.entry)) {
                    ref->death->work.type = BINDER_WORK_DEAD_BINDER;
                    list_add_tail(&ref->death->work.entry, &ref->proc->todo);
                    // 插入到binder_ref请求进程的binder线程等待队列????? 天然支持binder通信吗?
                    // 什么时候,需要死亡回调,自己也是binder服务?
                    wake_up_interruptible(&ref->proc->wait);
                }               
        ...
 }

Obituary is sent directly to the binder process Client-side on the queue, there seems to be useful only for each other todo C / S communication scenario, when the Client the binder thread wakes up, it will do some clean-up and rehabilitation work for the "obituary" :

static int
binder_thread_read(struct binder_proc *proc, struct binder_thread *thread,
    void  __user *buffer, int size, signed long *consumed, int non_block)
    {
        case BINDER_WORK_DEAD_BINDER:
                case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
                case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
                    struct binder_ref_death *death = container_of(w, struct binder_ref_death, work);
                    uint32_t cmd;
                    if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
                        cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
                    else
                        cmd = BR_DEAD_BINDER;
                    ...
 }

Here is written to the user space of a BR_DEAD_BINDER command and returns talkWithDriver function, upon return, IPCThreadState will continue executeCommand,

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    // 死亡讣告
    case BR_DEAD_BINDER:
        {
            BpBinder *proxy = (BpBinder*)mIn.readInt32();
            <!--关键点1 -->
            proxy->sendObituary();
            mOut.writeInt32(BC_DEAD_BINDER_DONE);
            mOut.writeInt32((int32_t)proxy);
        } break;



}

Critical Points 1, Obituary Obituary literal translation is, in fact, is the use of BpBinder send obituary, obituary after completion of the process, again Binder driver to send an acknowledgment.

void BpBinder::sendObituary()
{
    ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
        this, mHandle, mObitsSent ? "true" : "false");
    mAlive = 0;
    if (mObitsSent) return;
    mLock.lock();
    Vector<Obituary>* obits = mObituaries;
    if(obits != NULL) {
    <!--关键点1-->
        IPCThreadState* self = IPCThreadState::self();
        self->clearDeathNotification(mHandle, this);
        self->flushCommands();
        mObituaries = NULL;
    }
    mObitsSent = 1;
    mLock.unlock();
    if (obits != NULL) {
        const size_t N = obits->size();
        for (size_t i=0; i<N; i++) {
            reportOneDeath(obits->itemAt(i));
        }
        delete obits;
    }
}

Critical Points 1, here with the corresponding registration will clear itself from the observer list, and then after the report

void BpBinder::reportOneDeath(const Obituary& obit)
{
    sp<DeathRecipient> recipient = obit.recipient.promote();
    ALOGV("Reporting death to recipient: %p\n", recipient.get());
    if (recipient == NULL) return;

    recipient->binderDied(this);
}

Which in turn calls the callback upper DeathRecipient of logic do some clean-up and the like. To AMS for example, the binderDied function on the very complex, including the clean up some data, and even the reconstruction process, etc., are not discussed.

It is engaged in the development of the Android engineers for seven years, a lot of people ask me privately, 2019 Android how advanced the science, there is no method?

Yes, at the beginning I spent more than a month to sort out learning materials, hoping to help those who want to enhance the advanced Android development, but do not know how advanced learning friends. [ Including advanced UI, performance optimization, Architect courses, NDK, Kotlin, hybrid development (ReactNative + Weex), Flutter and other technical information architecture ], hoping to help review your pre-interview and find a good job, but also save in time they search for information online to learn.

Obtaining: Add Android architecture exchange QQ group chat: 513 088 520, into the group that is to receive the information! ! !

Click on the link to join a group chat Android mobile architecture [total population]: join a group chat

Sourcebook

Guess you like

Origin blog.csdn.net/weixin_45136073/article/details/93472756