diff --git a/03_day.pptx b/03_day.pptx index 9556bf3..225393e 100644 Binary files a/03_day.pptx and b/03_day.pptx differ diff --git a/03_day/binder_1/Android.bp b/03_day/binder_1/Android.bp index e32ec4d..f834b34 100644 --- a/03_day/binder_1/Android.bp +++ b/03_day/binder_1/Android.bp @@ -1,5 +1,5 @@ cc_defaults { - name: "my_flags", + name: "my_flags_2", cflags: [ "-Wall", @@ -16,11 +16,20 @@ cc_defaults { } cc_binary { - name: "my_server_1", - defaults: ["my_flags"], + name: "my_server_2", + defaults: ["my_flags_2"], srcs: [ "my_server.c", "binder.c", ], } +cc_binary { + name: "my_client_2", + defaults: ["my_flags_2"], + srcs: [ + "my_client.c", + "binder.c", + ], +} + diff --git a/03_day/binder_1/my_client.c b/03_day/binder_1/my_client.c new file mode 100644 index 0000000..0acbd23 --- /dev/null +++ b/03_day/binder_1/my_client.c @@ -0,0 +1,54 @@ + +#include +#include +#include +#include + +#include "binder.h" + +uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) +{ + uint32_t handle; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bio_init(&msg, iodata, sizeof(iodata), 4); + bio_put_uint32(&msg, 0); // strict mode header + bio_put_string16_x(&msg, SVC_MGR_NAME); + bio_put_string16_x(&msg, name); + + if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) + return 0; + + handle = bio_get_ref(&reply); + + if (handle) + binder_acquire(bs, handle); + + binder_done(bs, &msg, &reply); + + return handle; +} + +int main(int argc, char **argv) +{ + struct binder_state *bs; + uint32_t svcmgr = BINDER_SERVICE_MANAGER; + uint32_t handle; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bs = binder_open("/dev/binder", 128*1024); + if (!bs) { + fprintf(stderr, "failed to open binder driver\n"); + return -1; + } + + handle = svcmgr_lookup(bs, svcmgr, argv[argc-1]); + fprintf(stderr,"lookup(%s) = %x\n", argv[argc-1], handle); + + bio_init(&msg, iodata, sizeof(iodata), 4); + + binder_call(bs, &msg, &reply, handle, 1); + return 0; +} diff --git a/03_day/binder_1/my_server.c b/03_day/binder_1/my_server.c index eecbae4..d69e16d 100644 --- a/03_day/binder_1/my_server.c +++ b/03_day/binder_1/my_server.c @@ -36,6 +36,17 @@ int my_handler(struct binder_state *bs, struct binder_io *reply) { printf("my_handler %p %p %p %p\n", bs, txn, msg, reply); + switch(txn->code) { + case 1: + printf("Server : LED_ON, %p\n", (void*)txn->target.ptr); + return 0; + + default: + printf("unknown code %d\n", txn->code); + return -1; + } + + bio_put_uint32(reply, 0); return 0; } @@ -53,6 +64,7 @@ int main(int argc, char **argv) return -1; } + printf("Server : &token = %p\n", &token ); svcmgr_publish(bs, svcmgr, argv[argc-1], &token); binder_loop(bs, my_handler); return 0; diff --git a/03_day/binder_2/Android.bp b/03_day/binder_2/Android.bp new file mode 100644 index 0000000..6b98eee --- /dev/null +++ b/03_day/binder_2/Android.bp @@ -0,0 +1,35 @@ +cc_defaults { + name: "my_flags_3", + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + product_variables: { + binder32bit: { + cflags: ["-DBINDER_IPC_32BIT=1"], + }, + }, + + shared_libs: ["liblog"], +} + +cc_binary { + name: "my_server_3", + defaults: ["my_flags_3"], + srcs: [ + "my_server.c", + "binder.c", + ], +} + +cc_binary { + name: "my_client_3", + defaults: ["my_flags_3"], + srcs: [ + "my_client.c", + "binder.c", + ], +} + diff --git a/03_day/binder_2/bctest.c b/03_day/binder_2/bctest.c new file mode 100644 index 0000000..354df67 --- /dev/null +++ b/03_day/binder_2/bctest.c @@ -0,0 +1,107 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#include +#include +#include +#include + +#include "binder.h" + +uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) +{ + uint32_t handle; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bio_init(&msg, iodata, sizeof(iodata), 4); + bio_put_uint32(&msg, 0); // strict mode header + bio_put_string16_x(&msg, SVC_MGR_NAME); + bio_put_string16_x(&msg, name); + + if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) + return 0; + + handle = bio_get_ref(&reply); + + if (handle) + binder_acquire(bs, handle); + + binder_done(bs, &msg, &reply); + + return handle; +} + +int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) +{ + int status; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bio_init(&msg, iodata, sizeof(iodata), 4); + bio_put_uint32(&msg, 0); // strict mode header + bio_put_string16_x(&msg, SVC_MGR_NAME); + bio_put_string16_x(&msg, name); + bio_put_obj(&msg, ptr); + + if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) + return -1; + + status = bio_get_uint32(&reply); + + binder_done(bs, &msg, &reply); + + return status; +} + +unsigned token; + +int main(int argc, char **argv) +{ + struct binder_state *bs; + uint32_t svcmgr = BINDER_SERVICE_MANAGER; + uint32_t handle; + + bs = binder_open("/dev/binder", 128*1024); + if (!bs) { + fprintf(stderr, "failed to open binder driver\n"); + return -1; + } + + argc--; + argv++; + while (argc > 0) { + if (!strcmp(argv[0],"alt")) { + handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); + if (!handle) { + fprintf(stderr,"cannot find alt_svc_mgr\n"); + return -1; + } + svcmgr = handle; + fprintf(stderr,"svcmgr is via %x\n", handle); + } else if (!strcmp(argv[0],"lookup")) { + if (argc < 2) { + fprintf(stderr,"argument required\n"); + return -1; + } + handle = svcmgr_lookup(bs, svcmgr, argv[1]); + fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle); + argc--; + argv++; + } else if (!strcmp(argv[0],"publish")) { + if (argc < 2) { + fprintf(stderr,"argument required\n"); + return -1; + } + svcmgr_publish(bs, svcmgr, argv[1], &token); + argc--; + argv++; + } else { + fprintf(stderr,"unknown command %s\n", argv[0]); + return -1; + } + argc--; + argv++; + } + return 0; +} diff --git a/03_day/binder_2/binder.c b/03_day/binder_2/binder.c new file mode 100644 index 0000000..93a18fc --- /dev/null +++ b/03_day/binder_2/binder.c @@ -0,0 +1,656 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#define LOG_TAG "Binder" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "binder.h" + +#define MAX_BIO_SIZE (1 << 30) + +#define TRACE 0 + +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(const char* driver, size_t mapsize) +{ + struct binder_state *bs; + struct binder_version vers; + + bs = malloc(sizeof(*bs)); + if (!bs) { + errno = ENOMEM; + return NULL; + } + + bs->fd = open(driver, O_RDWR | O_CLOEXEC); + if (bs->fd < 0) { + fprintf(stderr,"binder: cannot open %s (%s)\n", + driver, 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_free_buffer(struct binder_state *bs, + binder_uintptr_t buffer_to_free) +{ + struct { + uint32_t cmd_free; + binder_uintptr_t buffer; + } __attribute__((packed)) data; + data.cmd_free = BC_FREE_BUFFER; + data.buffer = buffer_to_free; + binder_write(bs, &data, sizeof(data)); +} + +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); + if (txn->flags & TF_ONE_WAY) { + binder_free_buffer(bs, txn->data.ptr.buffer); + } else { + 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, + __unused 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; +} diff --git a/03_day/binder_2/binder.h b/03_day/binder_2/binder.h new file mode 100644 index 0000000..69be94f --- /dev/null +++ b/03_day/binder_2/binder.h @@ -0,0 +1,73 @@ +/* Copyright 2008 The Android Open Source Project + */ +#ifndef _BINDER_H_ +#define _BINDER_H_ +#include +#include +struct binder_state; +struct binder_io +{ + char *data; /* pointer to read/write from */ + binder_size_t *offs; /* array of offsets */ + size_t data_avail; /* bytes available in data buffer */ + size_t offs_avail; /* entries available in offsets array */ + char *data0; /* start of data buffer */ + binder_size_t *offs0; /* start of offsets buffer */ + uint32_t flags; + uint32_t unused; +}; +struct binder_death { + void (*func)(struct binder_state *bs, void *ptr); + void *ptr; +}; +/* the one magic handle */ +#define BINDER_SERVICE_MANAGER 0U +#define SVC_MGR_NAME "android.os.IServiceManager" +enum { + /* Must match definitions in IBinder.h and IServiceManager.h */ + PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), + SVC_MGR_GET_SERVICE = 1, + SVC_MGR_CHECK_SERVICE, + SVC_MGR_ADD_SERVICE, + SVC_MGR_LIST_SERVICES, +}; +typedef int (*binder_handler)(struct binder_state *bs, + struct binder_transaction_data *txn, + struct binder_io *msg, + struct binder_io *reply); +struct binder_state *binder_open(const char* driver, size_t mapsize); +void binder_close(struct binder_state *bs); +/* initiate a blocking binder call + * - returns zero on success + */ +int binder_call(struct binder_state *bs, + struct binder_io *msg, struct binder_io *reply, + uint32_t target, uint32_t code); +/* release any state associate with the binder_io + * - call once any necessary data has been extracted from the + * binder_io after binder_call() returns + * - can safely be called even if binder_call() fails + */ +void binder_done(struct binder_state *bs, + struct binder_io *msg, struct binder_io *reply); +/* manipulate strong references */ +void binder_acquire(struct binder_state *bs, uint32_t target); +void binder_release(struct binder_state *bs, uint32_t target); +void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death); +void binder_loop(struct binder_state *bs, binder_handler func); +int binder_become_context_manager(struct binder_state *bs); +/* allocate a binder_io, providing a stack-allocated working + * buffer, size of the working buffer, and how many object + * offset entries to reserve from the buffer + */ +void bio_init(struct binder_io *bio, void *data, + size_t maxdata, size_t maxobjects); +void bio_put_obj(struct binder_io *bio, void *ptr); +void bio_put_ref(struct binder_io *bio, uint32_t handle); +void bio_put_uint32(struct binder_io *bio, uint32_t n); +void bio_put_string16(struct binder_io *bio, const uint16_t *str); +void bio_put_string16_x(struct binder_io *bio, const char *_str); +uint32_t bio_get_uint32(struct binder_io *bio); +uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz); +uint32_t bio_get_ref(struct binder_io *bio); +#endif diff --git a/03_day/binder_2/my_client.c b/03_day/binder_2/my_client.c new file mode 100644 index 0000000..3cddbfe --- /dev/null +++ b/03_day/binder_2/my_client.c @@ -0,0 +1,55 @@ + +#include +#include +#include +#include + +#include "binder.h" + +uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) +{ + uint32_t handle; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bio_init(&msg, iodata, sizeof(iodata), 4); + bio_put_uint32(&msg, 0); // strict mode header + bio_put_string16_x(&msg, SVC_MGR_NAME); + bio_put_string16_x(&msg, name); + + if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) + return 0; + + handle = bio_get_ref(&reply); + + if (handle) + binder_acquire(bs, handle); + + binder_done(bs, &msg, &reply); + + return handle; +} + +int main(int argc, char **argv) +{ + struct binder_state *bs; + uint32_t svcmgr = BINDER_SERVICE_MANAGER; + uint32_t handle; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bs = binder_open("/dev/binder", 128*1024); + if (!bs) { + fprintf(stderr, "failed to open binder driver\n"); + return -1; + } + + handle = svcmgr_lookup(bs, svcmgr, argv[argc-1]); + fprintf(stderr,"lookup(%s) = %x\n", argv[argc-1], handle); + + bio_init(&msg, iodata, sizeof(iodata), 4); + + binder_call(bs, &msg, &reply, handle, 1); + binder_call(bs, &msg, &reply, handle, 2); + return 0; +} diff --git a/03_day/binder_2/my_server.c b/03_day/binder_2/my_server.c new file mode 100644 index 0000000..cf3f3d7 --- /dev/null +++ b/03_day/binder_2/my_server.c @@ -0,0 +1,99 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#include +#include +#include +#include + +#include "binder.h" + +typedef struct +{ + void (*on)(void); + void (*off)(void); +} LED_INFO; + +int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) +{ + int status; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bio_init(&msg, iodata, sizeof(iodata), 4); + bio_put_uint32(&msg, 0); // strict mode header + bio_put_string16_x(&msg, SVC_MGR_NAME); + bio_put_string16_x(&msg, name); + bio_put_obj(&msg, ptr); + + if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) + return -1; + + status = bio_get_uint32(&reply); + + binder_done(bs, &msg, &reply); + + return status; +} + +int my_handler(struct binder_state *bs, + struct binder_transaction_data *txn, + struct binder_io *msg, + struct binder_io *reply) +{ + printf("my_handler %p %p %p %p\n", bs, txn, msg, reply); + LED_INFO *Led = (LED_INFO*)txn->target.ptr; + switch(txn->code) { + case 1: + { + Led->on(); + return 0; + } + case 2: + { + Led->off(); + return 0; + } + + default: + printf("unknown code %d\n", txn->code); + return -1; + } + + bio_put_uint32(reply, 0); + return 0; +} + +void ledOn(void) +{ + printf("Server : ledOn\n"); +} + +void ledOff(void) +{ + printf("Server : ledOff\n"); +} + +int main(int argc, char **argv) +{ + struct binder_state *bs; + uint32_t svcmgr = BINDER_SERVICE_MANAGER; + LED_INFO *Led; + + bs = binder_open("/dev/binder", 128*1024); + if (!bs) { + fprintf(stderr, "failed to open binder driver\n"); + return -1; + } + Led = (LED_INFO*)malloc( sizeof(LED_INFO) ); + Led->on = ledOn; + Led->off = ledOff; + + printf("Server : &token = %p\n", Led ); + svcmgr_publish(bs, svcmgr, argv[argc-1], Led); + binder_loop(bs, my_handler); + return 0; +} + + + diff --git a/03_day/sp/.sp.cpp.swp b/03_day/sp/.sp.cpp.swp new file mode 100644 index 0000000..776e948 Binary files /dev/null and b/03_day/sp/.sp.cpp.swp differ diff --git a/03_day/sp/a.out b/03_day/sp/a.out new file mode 100644 index 0000000..7c513b6 Binary files /dev/null and b/03_day/sp/a.out differ diff --git a/03_day/sp/sp.cpp b/03_day/sp/sp.cpp new file mode 100644 index 0000000..e7dbdd3 --- /dev/null +++ b/03_day/sp/sp.cpp @@ -0,0 +1,341 @@ +#if 1 +#include + +class AAA +{ + int mRefs; + public: + AAA():mRefs(0) { printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } + void incStrong() { + printf("AAA::incStrong() : mRefs=%d\n", ++mRefs); + } + void decStrong() + { + --mRefs; + printf("AAA::decStrong() : mRefs=%d\n", mRefs); + if( mRefs == 0 ) + delete this; + } +}; + +template < typename T > +class sp +{ + T *mPtr; + public: + sp( T *ptr):mPtr(ptr) { + printf("sp::sp(T)\n"); + mPtr->incStrong(); + } + sp( const sp &r ) : mPtr(r.mPtr) { + printf("sp::sp(sp)\n"); + mPtr->incStrong(); + } + + ~sp() { + printf("sp::~sp()\n"); + mPtr->decStrong(); + } + + T * operator->() + { + return mPtr; + } + T operator*() + { + return *mPtr; + } +}; + +int main() +{ + { + sp p1 = new AAA; + sp p2 = p1; + p1->foo(); + p2->foo(); + } + return 0; +} +#endif +#if 0 +#include + +class AAA +{ + public: + AAA() { printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; + +template < typename T > +class sp +{ + T *mPtr; + static int mRefs; + public: + sp( T *ptr):mPtr(ptr) { + mRefs=1; + printf("sp::sp(T), mRefs=%d\n", mRefs); + } + sp( const sp &r ) { + mRefs++; + printf("sp::sp(sp), mRefs=%d\n", mRefs); + } + + ~sp() { + printf("sp::~sp()\n"); + if( --mRefs == 0 ) + delete mPtr; + } + + T * operator->() + { + return mPtr; + } + T operator*() + { + return *mPtr; + } +}; + +template < typename T > +int sp::mRefs = 0; + +int main() +{ + { + sp p1 = new AAA; + sp p2 = p1; + p1->foo(); + p2->foo(); + } + return 0; +} +#endif +#if 0 +#include + +class AAA +{ + public: + AAA() { printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; + +template < typename T > +class sp +{ + T *mPtr; + public: + sp( T *ptr):mPtr(ptr) { printf("sp::sp()\n"); } + ~sp() { + printf("sp::~sp()\n"); + delete mPtr; + } + + T * operator->() + { + return mPtr; + } + T operator*() + { + return *mPtr; + } +}; + +int main() +{ + { + sp p1 = new AAA; + sp p2 = p1; + p1->foo(); + p2->foo(); + } + return 0; +} +#endif +#if 0 +#include + +class AAA +{ + public: + AAA() { printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; +class BBB +{ + public: + BBB() { printf("BBB::BBB()\n"); } + ~BBB() { printf("BBB::~BBB()\n"); } + void foo() { printf("BBB::foo()\n"); } +}; + +template < typename T > +class sp +{ + T *mPtr; + public: + sp( T *ptr):mPtr(ptr) { printf("sp::sp()\n"); } + ~sp() { + printf("sp::~sp()\n"); + delete mPtr; + } + + T * operator->() + { + return mPtr; + } + T operator*() + { + return *mPtr; + } +}; + +int main() +{ + { + sp pa = new AAA; + pa->foo(); + + sp pb = new BBB; + pb->foo(); + } + return 0; +} +#endif +#if 0 +#include + +class AAA +{ + public: + AAA() { printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; + +class sp +{ + AAA *mPtr; + public: + sp( AAA *ptr):mPtr(ptr) { printf("sp::sp()\n"); } + ~sp() { + printf("sp::~sp()\n"); + delete mPtr; + } + + AAA * operator->() + { + return mPtr; + } + AAA operator*() + { + return *mPtr; + } +}; + +int main() +{ + { + sp pa = new AAA; + pa->foo(); // pa.operator->()->foo(); + + (*pa).foo(); + } + return 0; +} +#endif +#if 0 +#include + +class AAA +{ + public: + AAA() { printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; + +class sp +{ + AAA *mPtr; + public: + sp( AAA *ptr):mPtr(ptr) { printf("sp::sp()\n"); } + ~sp() { + printf("sp::~sp()\n"); + delete mPtr; + } +}; + +int main() +{ + { + //AAA* pa = new AAA; + //pa->foo(); + sp pa = new AAA; + pa->foo(); // pa.operator->()->foo(); + } + return 0; +} +#endif + +#if 0 +#include + +class AAA +{ + public: + AAA() { printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } +}; + +int main() +{ + AAA *pa = new AAA; + //... + return 0; +} +#endif + +#if 0 +#include + +class AAA +{ + public: + AAA() { printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } +}; + +int main() +{ + AAA *pa = new AAA; + delete pa; + //... + return 0; +} +#endif + +#if 0 +#include + +class AAA +{ + public: + AAA() { printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } +}; + +int main() +{ + AAA aaa; + return 0; +} +#endif