Android Development Long distance ix--thoroughly master binder

Source: Internet
Author: User
Tags mremote

This article is a series of articles, I am in the long-distance development of Android a little thoughts and records, I will try to follow the first easy after the difficult sequence to write the series. The series cited the "Android Development art exploration" and "in-depth understanding of Android volume Ⅰ,ⅱ,ⅲ" in the relevant knowledge, in addition to learn from other high-quality blog, here to the great God to thank you, worship!!! In addition, this article series of knowledge may require a certain Android Development Foundation and project experience to better understand, that is, the series of articles for Android Advanced Development engineer.

Objective

Last time it was better not to say to the interview, it is expected to hang, data structure and algorithm although the interview before a wave, but the time is too short, then learned is not good. Also some knowledge of Android is not very well understood. But it also increased my motivation to write blogs. A lot of knowledge always feel that they have a good grasp of, but the more detailed aspects of the question is not very clear. So the purpose of writing this whole blog is to deepen their knowledge, develop their own communication skills, and we learn together.
Well, gossip less, we first solve the problem left behind in the last article, then there is time, I put this interview experience to write a blog, and we encourage each other.
Let's look at ServiceManager in this article. Not much of it in the previous article, ServiceManager as a big housekeeper for Android services. It is still necessary for us to take a look at it.

ServiceManager Overview

ServiceManager is the big butler for all the important system services in the Android world. As mentioned earlier in the AMS (Activitymanagerservice), there are many packagemanagerservice that may be analyzed later, and so on, and so on, and so on need to register like ServiceManager. So why do we need a servicemanager, and what is the important role of it? The following points are considered to be private:

    1. ServiceManager can centrally manage all the services within the system, it can impose permissions control, not any process can register the service.
    2. ServiceManager supports finding the corresponding service by string name. This function is much like DNS. The server process may be unpredictable due to various reasons. If you let each client go to the test, the pressure is too great. Now with a unified management organization, the client only need to query ServiceManager, you can grasp the trend, get the latest information.
ServiceManager

[Systemserver.java]

public void setSystemProcess() {    try {        //注册服务,第二个参数为this,这里假设SystemServer通过“socket”与SM交互        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);        ..........    } catch (PackageManager.NameNotFoundException e) {        ........    }}

In our Systemserver process, AMS interacts with the SM process via SM's agent (the reader can also imagine the process as a way of communicating between processes, such as pipelines, sockets, etc.) and registering itself in SM. In this case, we use the ServiceManager agent to interact with the SM process, since there is a proxy, then we have to have a corresponding server. So according to our previous blog Thinking analysis, is the following process:

How did the ServiceManager start?

According to our previous blog ideas, we have a servicemanager agent on the systemserver side, Then the Android system should provide inheritance like AMS or indirectly inherit from Java layer Binder and then rewrite the Ontransact method to handle the request. However, ServiceManager does not use a complex binder class structure such as AMS. Instead, they deal directly with binder-driven devices. So our last article said ServiceManager is not the same. Let's look at the specifics.

ServiceManager is configured to start in the Init.rc configuration file and is a program written in the C + + language. Init process, SM process and other relationships such as


Let's look at its main method.

int main(int argc, char **argv){    struct binder_state *bs;    //①应该是打开binder设备吧?    bs = binder_open(128*1024);    if (!bs) {        ALOGE("failed to open binder driver\n");        return -1;    }    //②成为manager    if (binder_become_context_manager(bs)) {        ALOGE("cannot become context manager (%s)\n", strerror(errno));        return -1;    }   ......        //③处理客户端发过来的请求    binder_loop(bs, svcmgr_handler);    return 0;}
① Open Binder Device

[BINDER.C]

struct binder_state*binder_open(unsigned mapsize){    struct binder_state*bs;    bs=malloc(sizeof(*bs));    ......    //打开Binder设备    bs->fd=open("/dev/binder",O_RDWR);    ......    bs->mapsize=mapsize;    //进行内存映射    bs->mapped=mmap(NULL,mapsize,PROT_READ,MAP_PRIVATE,bs->    fd,0);}

The goal of this step is to map the binder driver of the kernel layer to the user space. We know that the process is independent, and the process runs in the user space, and the binder driver of the kernel layer can be seen as a file (in fact it is also a file on Linux). This step can be seen as mapping a file to user space, where our process interacts with this file.

② become manager

[BINDER.C]

int binder_become_context_manager(struct binder_state*bs){    //实现太简单了!这个有个0,什么鬼?    return ioctl(bs->fd,BINDER_SET_CONTEXT_MGR,0);}
③ processing requests sent by clients

[BINDER.C]

  void Binder_loop (struct binder_state *bs, binder_handler func) {int res;    struct Binder_write_read BWR;    uint32_t readbuf[32];    bwr.write_size = 0;    bwr.write_consumed = 0;    Bwr.write_buffer = 0;    Readbuf[0] = Bc_enter_looper;    Binder_write (BS, Readbuf, sizeof (uint32_t)); for (;;)        {//is a cyclic bwr.read_size = sizeof (READBUF);        bwr.read_consumed = 0;        Bwr.read_buffer = (uintptr_t) readbuf;        res = IOCTL (BS->FD, Binder_write_read, &BWR);            if (Res < 0) {Aloge ("Binder_loop:ioctl failed (%s) \ n", Strerror (errno));        Break }//Receive a request to Binder_parse, eventually calling Func to process these requests res = Binder_parse (BS, 0, (uintptr_t) readbuf, bwr.read_consumed, F        UNC); if (res = = 0) {aloge ("binder_loop:unexpected reply?!            \ n ");        Break            } if (Res < 0) {aloge ("Binder_loop:io error%d%s\n", Res, strerror (errno));        Break }    }}

The SVCMGR_ handler function pointer is passed in to the Func, so the client's request is processed centrally in the Svcmgr_handler.

[SERVICE_MANAGER.C]

int Svcmgr_handler (struct binder_state *bs, struct binder_transaction_data *txn, Struc    T binder_io *msg, struct binder_io *reply) {struct Svcinfo *si;    uint16_t *s;    size_t Len;    uint32_t handle;    uint32_t Strict_policy;        int allow_isolated;    if (txn->target.ptr! = Binder_service_manager) return-1;       if (Txn->code = = ping_transaction) return 0;    Strict_policy = Bio_get_uint32 (msg);    s = Bio_get_string16 (msg, &len);    if (s = = NULL) {return-1;        if (len! = (sizeof (svcmgr_id)/2)) | |        MEMCMP (svcmgr_id, S, sizeof (SVCMGR_ID))) {fprintf (stderr, "Invalid ID%s\n", str8 (S, Len));    return-1; } if (Sehandle && selinux_status_updated () > 0) {struct Selabel_handle *tmp_sehandle = Selinux_andro        Id_service_context_handle ();            if (tmp_sehandle) {selabel_close (sehandle);        Sehandle = Tmp_sehandle; }    }    Switch (txn->code) {case svc_mgr_get_service://gets the information for a service, and the service is represented by a string.        Case svc_mgr_check_service:s = Bio_get_string16 (msg, &len);//s is the SERVICE name represented by the string.        if (s = = NULL) {return-1;        } handle = Do_find_service (BS, S, Len, Txn->sender_euid, txn->sender_pid);        if (!handle) break;        Bio_put_ref (reply, handle);    return 0;        Case svc_mgr_add_service://corresponds to AddService request.        s = Bio_get_string16 (msg, &len);        if (s = = NULL) {return-1;        } handle = Bio_get_ref (msg); allow_isolated = Bio_get_uint32 (msg)?        1:0; if (Do_add_service (BS, S, Len, handle, Txn->sender_euid, allow_isolated, txn->sender_pid)) ret        urn-1;    Break        Case svc_mgr_list_services: {//Get the name of all service that is already registered with the current system.        uint32_t n = bio_get_uint32 (msg); if (!svc_can_list (txn->sender_pid)) {Aloge ("List_service () uid=%d-permission DENIed\n ", txn->sender_euid);        return-1;        } si = svclist;        while ((n--> 0) && si) si = si->next;            if (SI) {bio_put_string16 (reply, si->name);        return 0;    } return-1;        } default:aloge ("Unknown Code%d\n", Txn->code);    return-1;    } bio_put_uint32 (reply, 0); return 0;}
How are ServiceManager's agents obtained?

Let's go back to the initial call

[Systemserver.java]

public void setSystemProcess() {    try {        //注册服务,第二个参数为this,这里假设SystemServer通过“socket”与SM交互        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);        ..........    } catch (PackageManager.NameNotFoundException e) {        ........    }}

The above request was finally sent through the SM service agent, how did the agent come from? Let's see.

[Servicemanager.java]

public static void addService(String name, IBinder service) {    try {        getIServiceManager().addService(name, service, false);    } catch (RemoteException e) {        Log.e(TAG, "error in addService", e);    }}private static IServiceManager getIServiceManager() {    if (sServiceManager != null) {        return sServiceManager;    }    // 是这里,没错了    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());    return sServiceManager;}

Let's see Binderinternal.getcontextobject first ()

[Binderinternal.java]

//好吧,它还是个native函数public static final native IBinder getContextObject();

Follow up [android_ Util_binder.cpp]

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz){    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);    return javaObjectForIBinder(env, b);}

Follow up [ProcessState.cpp]

Sp<ibinder> processstate::getcontextobject (const sp<ibinder>&/*caller*/) {return Getstrongproxyforhandle (0);} /* This function is not we have seen before */sp<ibinder> Processstate::getstrongproxyforhandle (int32_t handle) {sp<ibinder> result    ;    Automutex _l (MLock);    handle_entry* e = lookuphandlelocked (handle);        if (E! = NULL) {ibinder* b = e->binder;                                if (b = = NULL | |!e->refs->attemptincweak (this)) {if (handle = = 0) {//Here our handle is 0            Parcel data; When the handle corresponding Bpbinder is first created//a virtual transaction request is executed to ensure that ServiceManager is registered status_t status = Ipcthreadstate                :: Self ()->transact (0, IBinder::P ing_transaction, data, NULL, 0); if (status = = Dead_object) return null;//If the ServiceManager is not registered, return directly}//here or in handle             The parameter created Bpbinder b = new Bpbinder (handle);            E->binder = b; if (b) e->Refs = B->getweakrefs ();        result = B;            } else {result.force_set (b);        E->refs->decweak (this); }} return result;

We step back
[android_ Util_binder.cpp]

Static Jobject Android_os_binderinternal_getcontextobject (jnienv* env, Jobject clazz) {sp<ibinder> b = ProcessSta    Te::self ()->getcontextobject (NULL);    Here's B = new Bpbinder (0); Return Javaobjectforibinder (env, b);} /* This function we have seen in the last article */jobject Javaobjectforibinder (jnienv* env, const sp<ibinder>& val) {if (val = = NULL) retur    n NULL;        If Val is a Binder object, enter the following branch, at which point Val is Bpbinder if (Val->checksubclass (&gbinderoffsets)) {//one of our own!        Jobject object = static_cast<javabbinder*> (Val.get ())->object ();        Logdeath ("Objectforbinder%p:it s our own%p!\n", Val.get (), object);    return object; } .../////The Findobject function that calls Bpbinder//has a objectmanager in native layer Bpbinder, which is used to manage Java native created on Bpbinder BINDERPR The Oxy object//findobject is used to determine whether a Java Binderproxy object that has been managed by ObjectManager is stored in gbinderproxyoffsets jobject objects = (jobject) val-    >findobject (&gbinderproxyoffsets); if (Object! = NULL) {Jobject res = JNIGetreferent (env, object);        ...//If the Java Binderproxy is already managed, delete the old Binderproxy Android_atomic_dec (&gnumproxyrefs);;        Val->detachobject (&gbinderproxyoffsets);    Env->deleteglobalref (object);    }//Create a new Binderproxy object = Env->newobject (Gbinderproxyoffsets.mclass, gbinderproxyoffsets.mconstructor);        if (Object! = NULL) {Env->setlongfield (object, Gbinderproxyoffsets.mobject, (Jlong) val.get ());               Val->incstrong ((void*) javaobjectforibinder);        Jobject refobject = Env->newglobalref (Env->getobjectfield (object, gbinderproxyoffsets.mself)); The newly created Binderproxy object is registered to the ObjectManager of Bpbinder, while registering a collection function Proxy_cleanup//When Binderproxy object detach, the Proxy_cleanup function is Called to release some resources val->attachobject (&gbinderproxyoffsets, Refobject, JNIENV_TO_JAVAVM (env), PROXY_CL        Eanup); Also Remember the death recipients registered on this proxy sp<deathrecipientlist> DRL = new Deathrecipientlist;        Drl->incstrong ((void*) javaobjectforibinder); Associate death notice list with Binderproxy Env->setlongfield (object, Gbinderproxyoffsets.morgue, Reinterpret_cast<jlong        > (Drl.get ()));        Note that a new object reference has been created.        Android_atomic_inc (&gnumproxyrefs);        garbage collection related; Number of binderproxy created with Gnumrefscreated Records//When the number of binderproxy created is greater than 200, the function will take advantage of Binderinternal's FORCEGC function for a garbage collection        Increfscreated (env);    return object; }}

then return to [Servicemanager.java]

private static IServiceManager getIServiceManager() {    if (sServiceManager != null) {        return sServiceManager;    }    // 是这里,没错了BinderInternal.getContextObject()是BinderProxy对象    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());    return sServiceManager;}

Follow up [[Servicemanagernative.java]]

static public IServiceManager asInterface(IBinder obj){    if (obj == null) {        return null;    }    我们知道这里的obj指向的是BinderProxy对象    IServiceManager in =        (IServiceManager)obj.queryLocalInterface(descriptor);    if (in != null) {        return in;    }        return new ServiceManagerProxy(obj);}

Follow up [Binder.java]

final class BinderProxy implements IBinder {       public IInterface queryLocalInterface(String descriptor) {        return null;    }}

Follow up [Servicemanagernative.java]

class ServiceManagerProxy implements IServiceManager {    public ServiceManagerProxy(IBinder remote) {        //这里的mRemote指向了BinderProxy,与我们上一篇博客中讲述的遥相呼应        mRemote = remote;    }}
Summary of this section

We gave a detailed account of the start of the SM process and its significance as a service butler. Together with the contents of the previous article, we have finally made a clearer story of binder.

Binder Supplement Note aidl

As described above, you should understand that in the Java Layer Binder architecture, the BP side can send requests to the BN side via the Binderproxy transact () method, while the BN end receives and processes requests from the BP side via the integrated Binder Rewrite Ontransact (). This structure is very clear and simple, in Android6.0, we can see the design everywhere, such as our activitymanagernavtive this class, involving binder communication is basically this design. But if we want to define some remote services for ourselves. That's a tedious way of writing, fortunately Android provides Aidl, and after Android8.0, we can see that many of the classes similar to activitymanagernavtive have been labeled obsolete, because the Android system also uses Aidl.
The syntax of aidl is very similar to defining a Java interface. I'm going to make a very simple aidl.

Imyaidlinterface.aidl

interface IMyAidlInterface {    int getTest();}

Then basically, we'll get a
Imyaidlinterface.java file after the build, which is generated by the Aidl tool, and we're using the basic Androidstudio, Even if you're using Eclipse, this file will be generated automatically, and you don't need to worry about it. But let's just take a look at the file we generated

Public interface Imyaidlinterface extends Android.os.IInterface {///Abstract stub class, inherits from Binder and implements our defined Imyaidlinterface interface//Relay From Binder, rewriting the Ontransact method, is not feeling with our xxxnative much like public static abstract class Stub extends Android.os.Binder implements COM . mafeibiao.testapplication.IMyAidlInterface {private static final java.lang.String descriptor = "Com.mafeibiao.tes Tapplication.        Imyaidlinterface ";         /** * Construct The stub at attach it to the interface.        */Public Stub () {this.attachinterface (this, descriptor); }/** * Cast an IBinder object to an Com.mafeibiao.testapplication.IMyAidlInterface interface, *         Generating a proxy if needed.  */public static com.mafeibiao.testapplication.IMyAidlInterface asinterface (Android.os.IBinder obj) {if ((obj = = null))            {return null;            } android.os.IInterface iin = Obj.querylocalinterface (descriptor); if (((iin! = null) && (iin instanceof Com.mafeibiao.testapplication.IMyAidlInterface)) {return (Com.mafeib            Iao.testapplication.IMyAidlInterface) iin);        } return new Com.mafeibiao.testapplication.IMyAidlInterface.Stub.Proxy (obj);        } @Override Public Android.os.IBinder Asbinder () {return this; } @Override public boolean ontransact (int code, ANDROID.OS.PARCEL data, android.os.Parcel reply, int flags)                    Throws android.os.RemoteException {switch (code) {case Interface_transaction: {                    Reply.writestring (descriptor);                return true;                    } case transaction_gettest: {data.enforceinterface (descriptor);                    int _result = This.gettest ();                    Reply.writenoexception ();                    Reply.writeint (_result);                return true;       }            }     Return Super.ontransact (Code, data, reply, flags); }/* This proxy needless to say is a proxy, there is a Mremote object inside it */private static class Proxy implements Com.mafeibiao.testappli cation.            Imyaidlinterface {private Android.os.IBinder mremote;            Proxy (Android.os.IBinder remote) {mremote = remote;            } @Override Public Android.os.IBinder Asbinder () {return mremote;            } public java.lang.String Getinterfacedescriptor () {return descriptor; } @Override public int gettest () throws Android.os.RemoteException {Android.os.Parce                L _data = Android.os.Parcel.obtain ();                Android.os.Parcel _reply = Android.os.Parcel.obtain ();                int _result;                    try {_data.writeinterfacetoken (descriptor);           Mremote.transact (Stub.transaction_gettest, _data, _reply, 0);         _reply.readexception ();                _result = _reply.readint ();                    } finally {_reply.recycle ();                _data.recycle ();            } return _result;    }} static final int transaction_gettest = (Android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } public int gettest () throws android.os.RemoteException;}

It can be seen that the nature of aidl is not fundamentally different from classes such as xxxnative, but his presence makes the work of building a binder service much simpler.

This article summarizes

In this article we analyzed in detail that Servicemanager,servicemanager does not use complex class structures, and he interacts directly with the binder driver to achieve the purpose of IPC communication. (The debt owed has finally been mended)

Next trailer

Let's take a look at the Android serialization-related knowledge in the next article.

Sincerely, salute.

Android Development Long distance ix--thoroughly master binder

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.