Android Process Communication --- Service Manager (1), android --- service

Source: Internet
Author: User

Android Process Communication --- Service Manager (1), android --- service

The Bind mechanism consists of four parts. Bind driver, Client, ServiceManager & Service

1. Bind is actually a linux-based driver for Memory Sharing.

The bind driver is biased towards the kernel, and the content of the bind mechanism is very large, so we will skip this part temporarily.

2. ServiceManager

As the name implies, Service Manager is a "Manager ". More specifically, it is the manager of all system services.

Start with service_manager.c \ frameworks \ native \ cmds \ servicemanager \ service_manager.c

static struct {    unsigned uid;    const char *name;} allowed[] = {    { AID_MEDIA, "media.audio_flinger" },    { AID_MEDIA, "media.log" },    { AID_MEDIA, "media.player" },    { AID_MEDIA, "media.camera" },    { AID_MEDIA, "media.audio_policy" },    { AID_DRM,   "drm.drmManager" },    { AID_NFC,   "nfc" },    { AID_BLUETOOTH, "bluetooth" },    { AID_RADIO, "radio.phone" },    { AID_RADIO, "radio.sms" },    { AID_RADIO, "radio.phonesubinfo" },    { AID_RADIO, "radio.simphonebook" },/* TODO: remove after phone services are updated: */    { AID_RADIO, "phone" },    { AID_RADIO, "sip" },    { AID_RADIO, "isms" },    { AID_RADIO, "iphonesubinfo" },    { AID_RADIO, "simphonebook" },    { AID_MEDIA, "common_time.clock" },    { AID_MEDIA, "common_time.config" },    { AID_KEYSTORE, "android.security.keystore" },};

The above is a part of the system service. These are all registered in servicemanager for management.

The service manager does the following:

I. Provide the IBind object, that is, the reference of each service for each process, and the Ibind object is unique for each process.

II. Register various system services in servicemanager.

 

 

 

Here, the binder driver is not the driver concept in our general operating system structure. It can be understood as a medium for communication between the client and ServiceManager.

The essence of the binder driver is Memory Sharing.

In fact, this is the front part of the entire bind mechanism, that is, from the client to servicemanager, so that the client can get the Ibind object and then directly "operate servie ".

For example:

AlarmManager alarmManager = context.getSystemService(Context.ALARM_SERVICE);        alarmManager.setExact(AlarmManager.ELAPSED_REALTIME, elapsedRealtime,                pendingIntent);

Obtain the alaram service bind object and then operate the "service" provided by the service ".

And this operation is synchronized!

It is like operating the same process.

Next, let's take a look at how service Manager implements the above.

2.1 Start Service Manager:

Since SM is an administrator, it should be the most diligent, that is, it must be started as early as possible.

Yes, its startup is defined in init. rc: \ system \ core \ rootdir \ init. rc

 

# adbd on at boot in emulatoron property:ro.kernel.qemu=1    start adbdservice servicemanager /system/bin/servicemanager    class core    user system    group system    critical    onrestart restart healthd    onrestart restart zygote    onrestart restart media    onrestart restart surfaceflinger    onrestart restart drm

What is Service Manager doing after it is started?

Or in service_manager.c:

int main(int argc, char **argv){    struct binder_state *bs;    void *svcmgr = BINDER_SERVICE_MANAGER;    bs = binder_open(128*1024);    if (binder_become_context_manager(bs)) {        ALOGE("cannot become context manager (%s)\n", strerror(errno));        return -1;    }    svcmgr_handle = svcmgr;    binder_loop(bs, svcmgr_handler);    return 0;}

Binder_open open the bind driver and allocate the size of KB.

Binder_become_context_manager (bs ):

int binder_become_context_manager(struct binder_state *bs){    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);}

Register yourself as a Service manager.

void binder_loop(struct binder_state *bs, binder_handler func){    int res;    struct binder_write_read bwr;    unsigned readbuf[32];    bwr.write_size = 0;    bwr.write_consumed = 0;    bwr.write_buffer = 0;        readbuf[0] = BC_ENTER_LOOPER;    binder_write(bs, readbuf, sizeof(unsigned));    for (;;) {        bwr.read_size = sizeof(readbuf);        bwr.read_consumed = 0;        bwr.read_buffer = (unsigned) readbuf;        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);        if (res < 0) {            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));            break;        }        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);        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;        }    }}

Start to enter the loop, which is similar to the previously analyzed andorid thread message driving mechanism.

Read the message queues, parse them, and know that an exception occurs.

Next, let's look at bind_parse:

int binder_parse(struct binder_state *bs, struct binder_io *bio,                 uint32_t *ptr, uint32_t size, binder_handler func){    int r = 1;    uint32_t *end = ptr + (size / 4);    while (ptr < end) {        uint32_t cmd = *ptr++;#if TRACE        fprintf(stderr,"%s:\n", cmd_name(cmd));#endif        switch(cmd) {        case BR_NOOP:            break;        case BR_TRANSACTION_COMPLETE:            break;        case BR_INCREFS:        case BR_ACQUIRE:        case BR_RELEASE:        case BR_DECREFS:#if TRACE            fprintf(stderr,"  %08x %08x\n", ptr[0], ptr[1]);#endif            ptr += 2;            break;        case BR_TRANSACTION: {            struct binder_txn *txn = (void *) ptr;            if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) {                ALOGE("parse: txn too small!\n");                return -1;            }            binder_dump_txn(txn);            if (func) {                unsigned rdata[256/4];                struct binder_io msg;                struct binder_io reply;                int res;                bio_init(&reply, rdata, sizeof(rdata), 4);                bio_init_from_txn(&msg, txn);                res = func(bs, txn, &msg, &reply);                binder_send_reply(bs, &reply, txn->data, res);            }            ptr += sizeof(*txn) / sizeof(uint32_t);            break;        }        case BR_REPLY: {            struct binder_txn *txn = (void*) ptr;            if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) {                ALOGE("parse: reply too small!\n");                return -1;            }            binder_dump_txn(txn);            if (bio) {                bio_init_from_txn(bio, txn);                bio = 0;            } else {                    /* todo FREE BUFFER */            }            ptr += (sizeof(*txn) / sizeof(uint32_t));            r = 0;            break;        }        case BR_DEAD_BINDER: {            struct binder_death *death = (void*) *ptr++;            death->func(bs, death->ptr);            break;        }        case BR_FAILED_REPLY:            r = -1;            break;        case BR_DEAD_REPLY:            r = -1;            break;        default:            ALOGE("parse: OOPS %d\n", cmd);            return -1;        }    }    return r;}

The key is analysis: BR_TRANSACTION, BR_REPLY.

BR_TRANSACTION is initialized, and then

res = func(bs, txn, &msg, &reply);binder_send_reply(bs, &reply, txn->data, res);

The func function is passed in service_manager.c.

int svcmgr_handler(struct binder_state *bs,                   struct binder_txn *txn,                   struct binder_io *msg,                   struct binder_io *reply)

Therefore, the bind_loop function for final analysis is the input function!

Now the entire service_manager process is clear.

Event-driven mechanism:

1. Read messages from the bind driver

2. process messages

3. log on to logoff and never exit until a fatal error occurs.

 

Int struct (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; uint32_t strict_policy; int allow_isolated; // ALOGI ("target = % p code = % d pid = % d uid = % d \ n", // txn-> target, txn-> code, txn-> sender_pid, txn-> sender_euid); if (txn-> target! = Svcmgr_handle) return-1; // Equivalent to Parcel: enforceInterface (), reading the RPC // header with the strict mode policy mask and the interface name. // Note that we ignore the strict_policy and don't propagate it // further (since we do no outbound RPCs anyway ). strict_policy = bio_get_uint32 (msg); s = bio_get_string16 (msg, & len); if (len! = (Sizeof (svcmgr_id)/2) | memcmp (svcmgr_id, s, sizeof (svcmgr_id) {fprintf (stderr, "invalid % s \ n ", str8 (s); return-1;} switch (txn-> code) {case SVC_MGR_GET_SERVICE: case SVC_MGR_CHECK_SERVICE: s = bio_get_string16 (msg, & len ); ptr = do_find_service (bs, s, len, txn-> sender_euid); if (! Ptr) break; bio_put_ref (reply, ptr); return 0; case SVC_MGR_ADD_SERVICE: s = bio_get_string16 (msg, & len); ptr = bio_get_ref (msg ); allow_isolated = bio_get_uint32 (msg )? 1: 0; if (do_add_service (bs, s, len, ptr, txn-> sender_euid, allow_isolated) return-1; break; case SVC_MGR_LIST_SERVICES: {unsigned n = bio_get_uint32 (msg); 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 ;}Svcmgr_handler

Switch statement to query and obtain the service or registration.

Check whether the service with the same name exists in the svclist.

Svclist is a linked list, which is the same as the thread message queue!

struct svcinfo *find_svc(uint16_t *s16, unsigned len){    struct svcinfo *si;    for (si = svclist; si; si = si->next) {        if ((len == si->len) &&            !memcmp(s16, si->name, len * sizeof(uint16_t))) {            return si;        }    }    return 0;}

Next let's take a look at void * do_find_service (struct binder_state * bs, uint16_t * s, unsigned len, unsigned uid)

What is return?

Registration Service: SVC_MGR_ADD_SERVICE:

 

Int do_add_service (struct binder_state * bs, uint16_t * s, unsigned len, void * ptr, unsigned uid, int allow_isolated) {struct svcinfo * si; // ALOGI ("add_service ('% s', % p, % s) uid = % d \ n", str8 (s), ptr, // allow_isolated? "Allow_isolated ":"! Allow_isolated ", uid); if (! Ptr | (len = 0) | (len> 127) return-1; if (! Svc_can_register (uid, s) {ALOGE ("add_service ('% s', % p) uid = % d-permission denied \ n", str8 (s), ptr, uid); return-1;} si = find_svc (s, len); if (si) {if (si-> ptr) {ALOGE ("add_service ('% s ', % p) uid = % d-already registered, OVERRIDE \ n ", str8 (s), ptr, uid); svcinfo_death (bs, si );} si-> ptr = ptr;} else {si = malloc (sizeof (* si) + (len + 1) * sizeof (uint16_t); if (! Si) {ALOGE ("add_service ('% s', % p) uid = % d-out of memory \ n", str8 (s), ptr, uid ); return-1;} 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-> allow_isolated = allow_isolated; si-> next = svclist; svclist = si;} binder_acquire (bs, ptr); binder_link_to_death (bs, ptr, & si-> death); return 0 ;}Do_add_service

Int svc_can_register (unsigned uid, uint16_t * name)

Determine whether it is in the allowed table.

First, check whether it is in the list?

Si = find_svc (s, len );

If no longer, register a new si to svclist.

Now service_manager is started.

Related Article

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.