123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640 |
- /* Copyright 2008 The Android Open Source Project
- */
- #include <inttypes.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/mman.h>
- #include "binder.h"
- #define MAX_BIO_SIZE (1 << 30)
- #define TRACE 0
- #define LOG_TAG "Binder"
- #include <cutils/log.h>
- void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn);
- #if TRACE
- void hexdump(void *_data, size_t len)
- {
- unsigned char *data = _data;
- size_t count;
- for (count = 0; count < len; count++) {
- if ((count & 15) == 0)
- fprintf(stderr,"%04zu:", count);
- fprintf(stderr," %02x %c", *data,
- (*data < 32) || (*data > 126) ? '.' : *data);
- data++;
- if ((count & 15) == 15)
- fprintf(stderr,"\n");
- }
- if ((count & 15) != 0)
- fprintf(stderr,"\n");
- }
- void binder_dump_txn(struct binder_transaction_data *txn)
- {
- struct flat_binder_object *obj;
- binder_size_t *offs = (binder_size_t *)(uintptr_t)txn->data.ptr.offsets;
- size_t count = txn->offsets_size / sizeof(binder_size_t);
- fprintf(stderr," target %016"PRIx64" cookie %016"PRIx64" code %08x flags %08x\n",
- (uint64_t)txn->target.ptr, (uint64_t)txn->cookie, txn->code, txn->flags);
- fprintf(stderr," pid %8d uid %8d data %"PRIu64" offs %"PRIu64"\n",
- txn->sender_pid, txn->sender_euid, (uint64_t)txn->data_size, (uint64_t)txn->offsets_size);
- hexdump((void *)(uintptr_t)txn->data.ptr.buffer, txn->data_size);
- while (count--) {
- obj = (struct flat_binder_object *) (((char*)(uintptr_t)txn->data.ptr.buffer) + *offs++);
- fprintf(stderr," - type %08x flags %08x ptr %016"PRIx64" cookie %016"PRIx64"\n",
- obj->type, obj->flags, (uint64_t)obj->binder, (uint64_t)obj->cookie);
- }
- }
- #define NAME(n) case n: return #n
- const char *cmd_name(uint32_t cmd)
- {
- switch(cmd) {
- NAME(BR_NOOP);
- NAME(BR_TRANSACTION_COMPLETE);
- NAME(BR_INCREFS);
- NAME(BR_ACQUIRE);
- NAME(BR_RELEASE);
- NAME(BR_DECREFS);
- NAME(BR_TRANSACTION);
- NAME(BR_REPLY);
- NAME(BR_FAILED_REPLY);
- NAME(BR_DEAD_REPLY);
- NAME(BR_DEAD_BINDER);
- default: return "???";
- }
- }
- #else
- #define hexdump(a,b) do{} while (0)
- #define binder_dump_txn(txn) do{} while (0)
- #endif
- #define BIO_F_SHARED 0x01 /* needs to be buffer freed */
- #define BIO_F_OVERFLOW 0x02 /* ran out of space */
- #define BIO_F_IOERROR 0x04
- #define BIO_F_MALLOCED 0x08 /* needs to be free()'d */
- struct binder_state
- {
- int fd;
- void *mapped;
- size_t mapsize;
- };
- struct binder_state *binder_open(size_t mapsize)
- {
- struct binder_state *bs;
- struct binder_version vers;
- bs = malloc(sizeof(*bs));
- if (!bs) {
- errno = ENOMEM;
- return NULL;
- }
- bs->fd = open("/dev/binder", O_RDWR);
- if (bs->fd < 0) {
- fprintf(stderr,"binder: cannot open device (%s)\n",
- strerror(errno));
- goto fail_open;
- }
- if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
- (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
- fprintf(stderr,
- "binder: kernel driver version (%d) differs from user space version (%d)\n",
- vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
- goto fail_open;
- }
- bs->mapsize = mapsize;
- bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
- if (bs->mapped == MAP_FAILED) {
- fprintf(stderr,"binder: cannot map device (%s)\n",
- strerror(errno));
- goto fail_map;
- }
- return bs;
- fail_map:
- close(bs->fd);
- fail_open:
- free(bs);
- return NULL;
- }
- void binder_close(struct binder_state *bs)
- {
- munmap(bs->mapped, bs->mapsize);
- close(bs->fd);
- free(bs);
- }
- int binder_become_context_manager(struct binder_state *bs)
- {
- return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
- }
- int binder_write(struct binder_state *bs, void *data, size_t len)
- {
- struct binder_write_read bwr;
- int res;
- bwr.write_size = len;
- bwr.write_consumed = 0;
- bwr.write_buffer = (uintptr_t) data;
- bwr.read_size = 0;
- bwr.read_consumed = 0;
- bwr.read_buffer = 0;
- res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
- if (res < 0) {
- fprintf(stderr,"binder_write: ioctl failed (%s)\n",
- strerror(errno));
- }
- return res;
- }
- void binder_send_reply(struct binder_state *bs,
- struct binder_io *reply,
- binder_uintptr_t buffer_to_free,
- int status)
- {
- struct {
- uint32_t cmd_free;
- binder_uintptr_t buffer;
- uint32_t cmd_reply;
- struct binder_transaction_data txn;
- } __attribute__((packed)) data;
- data.cmd_free = BC_FREE_BUFFER;
- data.buffer = buffer_to_free;
- data.cmd_reply = BC_REPLY;
- data.txn.target.ptr = 0;
- data.txn.cookie = 0;
- data.txn.code = 0;
- if (status) {
- data.txn.flags = TF_STATUS_CODE;
- data.txn.data_size = sizeof(int);
- data.txn.offsets_size = 0;
- data.txn.data.ptr.buffer = (uintptr_t)&status;
- data.txn.data.ptr.offsets = 0;
- } else {
- data.txn.flags = 0;
- data.txn.data_size = reply->data - reply->data0;
- data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
- data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
- data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
- }
- binder_write(bs, &data, sizeof(data));
- }
- int binder_parse(struct binder_state *bs, struct binder_io *bio,
- uintptr_t ptr, size_t size, binder_handler func)
- {
- int r = 1;
- uintptr_t end = ptr + (uintptr_t) size;
- while (ptr < end) {
- uint32_t cmd = *(uint32_t *) ptr;
- ptr += sizeof(uint32_t);
- #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," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *)));
- #endif
- ptr += sizeof(struct binder_ptr_cookie);
- break;
- case BR_TRANSACTION: {
- struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
- if ((end - ptr) < sizeof(*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.ptr.buffer, res);
- }
- ptr += sizeof(*txn);
- break;
- }
- case BR_REPLY: {
- struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
- if ((end - ptr) < sizeof(*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);
- r = 0;
- break;
- }
- case BR_DEAD_BINDER: {
- struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;
- ptr += sizeof(binder_uintptr_t);
- 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;
- }
- void binder_acquire(struct binder_state *bs, uint32_t target)
- {
- uint32_t cmd[2];
- cmd[0] = BC_ACQUIRE;
- cmd[1] = target;
- binder_write(bs, cmd, sizeof(cmd));
- }
- void binder_release(struct binder_state *bs, uint32_t target)
- {
- uint32_t cmd[2];
- cmd[0] = BC_RELEASE;
- cmd[1] = target;
- binder_write(bs, cmd, sizeof(cmd));
- }
- void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death)
- {
- struct {
- uint32_t cmd;
- struct binder_handle_cookie payload;
- } __attribute__((packed)) data;
- data.cmd = BC_REQUEST_DEATH_NOTIFICATION;
- data.payload.handle = target;
- data.payload.cookie = (uintptr_t) death;
- binder_write(bs, &data, sizeof(data));
- }
- int binder_call(struct binder_state *bs,
- struct binder_io *msg, struct binder_io *reply,
- uint32_t target, uint32_t code)
- {
- int res;
- struct binder_write_read bwr;
- struct {
- uint32_t cmd;
- struct binder_transaction_data txn;
- } __attribute__((packed)) writebuf;
- unsigned readbuf[32];
- if (msg->flags & BIO_F_OVERFLOW) {
- fprintf(stderr,"binder: txn buffer overflow\n");
- goto fail;
- }
- writebuf.cmd = BC_TRANSACTION;
- writebuf.txn.target.handle = target;
- writebuf.txn.code = code;
- writebuf.txn.flags = 0;
- writebuf.txn.data_size = msg->data - msg->data0;
- writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0);
- writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0;
- writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0;
- bwr.write_size = sizeof(writebuf);
- bwr.write_consumed = 0;
- bwr.write_buffer = (uintptr_t) &writebuf;
- hexdump(msg->data0, msg->data - msg->data0);
- for (;;) {
- 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) {
- fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));
- goto fail;
- }
- res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0);
- if (res == 0) return 0;
- if (res < 0) goto fail;
- }
- fail:
- memset(reply, 0, sizeof(*reply));
- reply->flags |= BIO_F_IOERROR;
- return -1;
- }
- 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 (;;) {
- 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;
- }
- res = binder_parse(bs, 0, (uintptr_t) 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;
- }
- }
- }
- void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn)
- {
- bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer;
- bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets;
- bio->data_avail = txn->data_size;
- bio->offs_avail = txn->offsets_size / sizeof(size_t);
- bio->flags = BIO_F_SHARED;
- }
- void bio_init(struct binder_io *bio, void *data,
- size_t maxdata, size_t maxoffs)
- {
- size_t n = maxoffs * sizeof(size_t);
- if (n > maxdata) {
- bio->flags = BIO_F_OVERFLOW;
- bio->data_avail = 0;
- bio->offs_avail = 0;
- return;
- }
- bio->data = bio->data0 = (char *) data + n;
- bio->offs = bio->offs0 = data;
- bio->data_avail = maxdata - n;
- bio->offs_avail = maxoffs;
- bio->flags = 0;
- }
- static void *bio_alloc(struct binder_io *bio, size_t size)
- {
- size = (size + 3) & (~3);
- if (size > bio->data_avail) {
- bio->flags |= BIO_F_OVERFLOW;
- return NULL;
- } else {
- void *ptr = bio->data;
- bio->data += size;
- bio->data_avail -= size;
- return ptr;
- }
- }
- void binder_done(struct binder_state *bs,
- struct binder_io *msg,
- struct binder_io *reply)
- {
- struct {
- uint32_t cmd;
- uintptr_t buffer;
- } __attribute__((packed)) data;
- if (reply->flags & BIO_F_SHARED) {
- data.cmd = BC_FREE_BUFFER;
- data.buffer = (uintptr_t) reply->data0;
- binder_write(bs, &data, sizeof(data));
- reply->flags = 0;
- }
- }
- static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio)
- {
- struct flat_binder_object *obj;
- obj = bio_alloc(bio, sizeof(*obj));
- if (obj && bio->offs_avail) {
- bio->offs_avail--;
- *bio->offs++ = ((char*) obj) - ((char*) bio->data0);
- return obj;
- }
- bio->flags |= BIO_F_OVERFLOW;
- return NULL;
- }
- void bio_put_uint32(struct binder_io *bio, uint32_t n)
- {
- uint32_t *ptr = bio_alloc(bio, sizeof(n));
- if (ptr)
- *ptr = n;
- }
- void bio_put_obj(struct binder_io *bio, void *ptr)
- {
- struct flat_binder_object *obj;
- obj = bio_alloc_obj(bio);
- if (!obj)
- return;
- obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj->type = BINDER_TYPE_BINDER;
- obj->binder = (uintptr_t)ptr;
- obj->cookie = 0;
- }
- void bio_put_ref(struct binder_io *bio, uint32_t handle)
- {
- struct flat_binder_object *obj;
- if (handle)
- obj = bio_alloc_obj(bio);
- else
- obj = bio_alloc(bio, sizeof(*obj));
- if (!obj)
- return;
- obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- obj->type = BINDER_TYPE_HANDLE;
- obj->handle = handle;
- obj->cookie = 0;
- }
- void bio_put_string16(struct binder_io *bio, const uint16_t *str)
- {
- size_t len;
- uint16_t *ptr;
- if (!str) {
- bio_put_uint32(bio, 0xffffffff);
- return;
- }
- len = 0;
- while (str[len]) len++;
- if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) {
- bio_put_uint32(bio, 0xffffffff);
- return;
- }
- /* Note: The payload will carry 32bit size instead of size_t */
- bio_put_uint32(bio, (uint32_t) len);
- len = (len + 1) * sizeof(uint16_t);
- ptr = bio_alloc(bio, len);
- if (ptr)
- memcpy(ptr, str, len);
- }
- void bio_put_string16_x(struct binder_io *bio, const char *_str)
- {
- unsigned char *str = (unsigned char*) _str;
- size_t len;
- uint16_t *ptr;
- if (!str) {
- bio_put_uint32(bio, 0xffffffff);
- return;
- }
- len = strlen(_str);
- if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) {
- bio_put_uint32(bio, 0xffffffff);
- return;
- }
- /* Note: The payload will carry 32bit size instead of size_t */
- bio_put_uint32(bio, len);
- ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t));
- if (!ptr)
- return;
- while (*str)
- *ptr++ = *str++;
- *ptr++ = 0;
- }
- static void *bio_get(struct binder_io *bio, size_t size)
- {
- size = (size + 3) & (~3);
- if (bio->data_avail < size){
- bio->data_avail = 0;
- bio->flags |= BIO_F_OVERFLOW;
- return NULL;
- } else {
- void *ptr = bio->data;
- bio->data += size;
- bio->data_avail -= size;
- return ptr;
- }
- }
- uint32_t bio_get_uint32(struct binder_io *bio)
- {
- uint32_t *ptr = bio_get(bio, sizeof(*ptr));
- return ptr ? *ptr : 0;
- }
- uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz)
- {
- size_t len;
- /* Note: The payload will carry 32bit size instead of size_t */
- len = (size_t) bio_get_uint32(bio);
- if (sz)
- *sz = len;
- return bio_get(bio, (len + 1) * sizeof(uint16_t));
- }
- static struct flat_binder_object *_bio_get_obj(struct binder_io *bio)
- {
- size_t n;
- size_t off = bio->data - bio->data0;
- /* TODO: be smarter about this? */
- for (n = 0; n < bio->offs_avail; n++) {
- if (bio->offs[n] == off)
- return bio_get(bio, sizeof(struct flat_binder_object));
- }
- bio->data_avail = 0;
- bio->flags |= BIO_F_OVERFLOW;
- return NULL;
- }
- uint32_t bio_get_ref(struct binder_io *bio)
- {
- struct flat_binder_object *obj;
- obj = _bio_get_obj(bio);
- if (!obj)
- return 0;
- if (obj->type == BINDER_TYPE_HANDLE)
- return obj->handle;
- return 0;
- }
|