From 7a0a2db279c9c08c96740badc6c524a773cfe0f2 Mon Sep 17 00:00:00 2001 From: ioacademy-jikim Date: Fri, 15 Jun 2018 10:55:16 +0900 Subject: [PATCH] 9 --- 04_day/binder_1/Android.bp | 35 ++ 04_day/binder_1/bctest.c | 107 +++++ 04_day/binder_1/binder.c | 656 +++++++++++++++++++++++++++++++ 04_day/binder_1/binder.h | 73 ++++ 04_day/binder_1/my_client.c | 54 +++ 04_day/binder_1/my_server.c | 74 ++++ 04_day/binder_2/Android.bp | 35 ++ 04_day/binder_2/bctest.c | 107 +++++ 04_day/binder_2/binder.c | 656 +++++++++++++++++++++++++++++++ 04_day/binder_2/binder.h | 73 ++++ 04_day/binder_2/my_client.c | 55 +++ 04_day/binder_2/my_server.c | 99 +++++ 04_day/binder_3/Android.bp | 15 + 04_day/binder_3/ProcessState.cpp | 54 +++ 04_day/binder_3/my_client.cpp | 22 ++ 04_day/binder_3/my_server.cpp | 38 ++ 04_day/binder_4/Android.bp | 16 + 04_day/binder_4/ILedService.cpp | 31 ++ 04_day/binder_4/ILedService.h | 26 ++ 04_day/binder_4/ProcessState.cpp | 54 +++ 04_day/binder_4/my_client.cpp | 23 ++ 04_day/binder_4/my_server.cpp | 38 ++ 04_day/binder_5/Android.bp | 18 + 04_day/binder_5/ILedService.cpp | 46 +++ 04_day/binder_5/ILedService.h | 41 ++ 04_day/binder_5/LedService.cpp | 10 + 04_day/binder_5/LedService.h | 13 + 04_day/binder_5/ProcessState.cpp | 54 +++ 04_day/binder_5/my_client.cpp | 23 ++ 04_day/binder_5/my_server.cpp | 22 ++ 04_day/binder_6/Android.bp | 21 + 04_day/binder_6/ILedClient.cpp | 49 +++ 04_day/binder_6/ILedClient.h | 41 ++ 04_day/binder_6/ILedService.cpp | 49 +++ 04_day/binder_6/ILedService.h | 42 ++ 04_day/binder_6/Led.cpp | 10 + 04_day/binder_6/Led.h | 13 + 04_day/binder_6/LedService.cpp | 11 + 04_day/binder_6/LedService.h | 13 + 04_day/binder_6/ProcessState.cpp | 54 +++ 04_day/binder_6/a.out | Bin 0 -> 8512 bytes 04_day/binder_6/my_client.cpp | 27 ++ 04_day/binder_6/my_server.cpp | 22 ++ 04_day/binder_6/thread.cpp | 43 ++ 04_day/sp/Android.bp | 7 + 04_day/sp/a.out | Bin 0 -> 14120 bytes 04_day/sp/sp.cpp | 409 +++++++++++++++++++ 04_day/sp/sp_1.cpp | 82 ++++ 04_day/sp/wp_1.cpp | 119 ++++++ 04_day/thread/.Thread.cpp.swp | Bin 0 -> 16384 bytes 04_day/thread/Android.bp | 8 + 04_day/thread/Thread.cpp | 261 ++++++++++++ 04_day/thread/a.out | Bin 0 -> 13400 bytes 53 files changed, 3849 insertions(+) create mode 100644 04_day/binder_1/Android.bp create mode 100644 04_day/binder_1/bctest.c create mode 100644 04_day/binder_1/binder.c create mode 100644 04_day/binder_1/binder.h create mode 100644 04_day/binder_1/my_client.c create mode 100644 04_day/binder_1/my_server.c create mode 100644 04_day/binder_2/Android.bp create mode 100644 04_day/binder_2/bctest.c create mode 100644 04_day/binder_2/binder.c create mode 100644 04_day/binder_2/binder.h create mode 100644 04_day/binder_2/my_client.c create mode 100644 04_day/binder_2/my_server.c create mode 100644 04_day/binder_3/Android.bp create mode 100644 04_day/binder_3/ProcessState.cpp create mode 100644 04_day/binder_3/my_client.cpp create mode 100644 04_day/binder_3/my_server.cpp create mode 100644 04_day/binder_4/Android.bp create mode 100644 04_day/binder_4/ILedService.cpp create mode 100644 04_day/binder_4/ILedService.h create mode 100644 04_day/binder_4/ProcessState.cpp create mode 100644 04_day/binder_4/my_client.cpp create mode 100644 04_day/binder_4/my_server.cpp create mode 100644 04_day/binder_5/Android.bp create mode 100644 04_day/binder_5/ILedService.cpp create mode 100644 04_day/binder_5/ILedService.h create mode 100644 04_day/binder_5/LedService.cpp create mode 100644 04_day/binder_5/LedService.h create mode 100644 04_day/binder_5/ProcessState.cpp create mode 100644 04_day/binder_5/my_client.cpp create mode 100644 04_day/binder_5/my_server.cpp create mode 100644 04_day/binder_6/Android.bp create mode 100644 04_day/binder_6/ILedClient.cpp create mode 100644 04_day/binder_6/ILedClient.h create mode 100644 04_day/binder_6/ILedService.cpp create mode 100644 04_day/binder_6/ILedService.h create mode 100644 04_day/binder_6/Led.cpp create mode 100644 04_day/binder_6/Led.h create mode 100644 04_day/binder_6/LedService.cpp create mode 100644 04_day/binder_6/LedService.h create mode 100644 04_day/binder_6/ProcessState.cpp create mode 100644 04_day/binder_6/a.out create mode 100644 04_day/binder_6/my_client.cpp create mode 100644 04_day/binder_6/my_server.cpp create mode 100644 04_day/binder_6/thread.cpp create mode 100644 04_day/sp/Android.bp create mode 100644 04_day/sp/a.out create mode 100644 04_day/sp/sp.cpp create mode 100644 04_day/sp/sp_1.cpp create mode 100644 04_day/sp/wp_1.cpp create mode 100644 04_day/thread/.Thread.cpp.swp create mode 100644 04_day/thread/Android.bp create mode 100644 04_day/thread/Thread.cpp create mode 100644 04_day/thread/a.out diff --git a/04_day/binder_1/Android.bp b/04_day/binder_1/Android.bp new file mode 100644 index 0000000..f834b34 --- /dev/null +++ b/04_day/binder_1/Android.bp @@ -0,0 +1,35 @@ +cc_defaults { + name: "my_flags_2", + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + product_variables: { + binder32bit: { + cflags: ["-DBINDER_IPC_32BIT=1"], + }, + }, + + shared_libs: ["liblog"], +} + +cc_binary { + 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/04_day/binder_1/bctest.c b/04_day/binder_1/bctest.c new file mode 100644 index 0000000..354df67 --- /dev/null +++ b/04_day/binder_1/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/04_day/binder_1/binder.c b/04_day/binder_1/binder.c new file mode 100644 index 0000000..93a18fc --- /dev/null +++ b/04_day/binder_1/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/04_day/binder_1/binder.h b/04_day/binder_1/binder.h new file mode 100644 index 0000000..69be94f --- /dev/null +++ b/04_day/binder_1/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/04_day/binder_1/my_client.c b/04_day/binder_1/my_client.c new file mode 100644 index 0000000..0acbd23 --- /dev/null +++ b/04_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/04_day/binder_1/my_server.c b/04_day/binder_1/my_server.c new file mode 100644 index 0000000..d69e16d --- /dev/null +++ b/04_day/binder_1/my_server.c @@ -0,0 +1,74 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#include +#include +#include +#include + +#include "binder.h" + +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); + 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; +} + +unsigned token; + + +int main(int argc, char **argv) +{ + struct binder_state *bs; + uint32_t svcmgr = BINDER_SERVICE_MANAGER; + + bs = binder_open("/dev/binder", 128*1024); + if (!bs) { + fprintf(stderr, "failed to open binder driver\n"); + 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/04_day/binder_2/Android.bp b/04_day/binder_2/Android.bp new file mode 100644 index 0000000..6b98eee --- /dev/null +++ b/04_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/04_day/binder_2/bctest.c b/04_day/binder_2/bctest.c new file mode 100644 index 0000000..354df67 --- /dev/null +++ b/04_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/04_day/binder_2/binder.c b/04_day/binder_2/binder.c new file mode 100644 index 0000000..93a18fc --- /dev/null +++ b/04_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/04_day/binder_2/binder.h b/04_day/binder_2/binder.h new file mode 100644 index 0000000..69be94f --- /dev/null +++ b/04_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/04_day/binder_2/my_client.c b/04_day/binder_2/my_client.c new file mode 100644 index 0000000..3cddbfe --- /dev/null +++ b/04_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/04_day/binder_2/my_server.c b/04_day/binder_2/my_server.c new file mode 100644 index 0000000..cf3f3d7 --- /dev/null +++ b/04_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/04_day/binder_3/Android.bp b/04_day/binder_3/Android.bp new file mode 100644 index 0000000..f3030c0 --- /dev/null +++ b/04_day/binder_3/Android.bp @@ -0,0 +1,15 @@ +cc_binary { + name: "my_server_cpp_1", + shared_libs: ["liblog", "libutils", "libbinder"], + srcs: [ + "my_server.cpp", + ], +} + +cc_binary { + name: "my_client_cpp_1", + shared_libs: ["liblog", "libutils", "libbinder"], + srcs: [ + "my_client.cpp", + ], +} diff --git a/04_day/binder_3/ProcessState.cpp b/04_day/binder_3/ProcessState.cpp new file mode 100644 index 0000000..07b6867 --- /dev/null +++ b/04_day/binder_3/ProcessState.cpp @@ -0,0 +1,54 @@ +#if 1 +#include +class ProcessState +{ + static ProcessState *gProcess; + ProcessState() + { + printf("fd=open(\"/dev/binder\", O_RDWR)\n"); + } + public: + static ProcessState *self() + { + if( gProcess == 0 ) + gProcess = new ProcessState; + return gProcess; + } + ~ProcessState() + { + printf("close(fd)\n"); + } +}; +ProcessState *ProcessState::gProcess = 0; + +int main() +{ + ProcessState *p1 = ProcessState::self(); + ProcessState *p2 = ProcessState::self(); + //ProcessState process; + return 0; +} +#endif + +#if 0 +#include +class ProcessState +{ + public: + ProcessState() + { + printf("fd=open(\"/dev/binder\", O_RDWR)\n"); + } + ~ProcessState() + { + printf("close(fd)\n"); + } +}; + +int main() +{ + ProcessState p1; + ProcessState p2; + return 0; +} +#endif diff --git a/04_day/binder_3/my_client.cpp b/04_day/binder_3/my_client.cpp new file mode 100644 index 0000000..d948117 --- /dev/null +++ b/04_day/binder_3/my_client.cpp @@ -0,0 +1,22 @@ + +#include +#include +#include +#include +#include + +using namespace android; + +int main() +{ + sp proc(ProcessState::self()); + sp sm(defaultServiceManager()); + sp binder = sm->getService( String16("led.service") ); + Parcel data, reply; + binder->transact(1, data, &reply); + + return 0; +} + + + diff --git a/04_day/binder_3/my_server.cpp b/04_day/binder_3/my_server.cpp new file mode 100644 index 0000000..d2481ff --- /dev/null +++ b/04_day/binder_3/my_server.cpp @@ -0,0 +1,38 @@ + +#include +#include +#include +#include +#include + +using namespace android; + +class LedService : public BBinder +{ + public: + status_t onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) + { + switch (code) { + case 1: + printf("LedService::LED_ON\n"); + return NO_ERROR; + + default: + return BBinder::onTransact(code, data, reply, flags); + } + } +}; + +int main() +{ + sp proc(ProcessState::self()); + sp sm(defaultServiceManager()); + sm->addService( String16("led.service"), new LedService ); + IPCThreadState::self()->joinThreadPool(); + + return 0; +} + + + diff --git a/04_day/binder_4/Android.bp b/04_day/binder_4/Android.bp new file mode 100644 index 0000000..a2a327c --- /dev/null +++ b/04_day/binder_4/Android.bp @@ -0,0 +1,16 @@ +cc_binary { + name: "my_server_cpp_2", + shared_libs: ["liblog", "libutils", "libbinder"], + srcs: [ + "my_server.cpp", + ], +} + +cc_binary { + name: "my_client_cpp_2", + shared_libs: ["liblog", "libutils", "libbinder"], + srcs: [ + "my_client.cpp", + "ILedService.cpp", + ], +} diff --git a/04_day/binder_4/ILedService.cpp b/04_day/binder_4/ILedService.cpp new file mode 100644 index 0000000..6183bd5 --- /dev/null +++ b/04_day/binder_4/ILedService.cpp @@ -0,0 +1,31 @@ +#define LOG_TAG "LedService" + +#include "ILedService.h" + +#include +#include +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class BpLedService : public BpInterface +{ +public: + explicit BpLedService(const sp& impl) + : BpInterface(impl) + { + } + + virtual void ledOn(void) + { + printf("BpLedService::ledOn()\n"); + Parcel data, reply; + remote()->transact(LED_ON, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(LedService, "android.os.ILedService"); + +}; // namespace android diff --git a/04_day/binder_4/ILedService.h b/04_day/binder_4/ILedService.h new file mode 100644 index 0000000..fb6b1c1 --- /dev/null +++ b/04_day/binder_4/ILedService.h @@ -0,0 +1,26 @@ +#ifndef ANDROID_ILED_SERVICE_H +#define ANDROID_ILED_SERVICE_H + +#include +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class ILedService : public IInterface +{ +public: + DECLARE_META_INTERFACE(LedService) + + virtual void ledOn() = 0; + + enum { + LED_ON = IBinder::FIRST_CALL_TRANSACTION + }; +}; + +}; // namespace android + +#endif // ANDROID_ISERVICE_MANAGER_H + diff --git a/04_day/binder_4/ProcessState.cpp b/04_day/binder_4/ProcessState.cpp new file mode 100644 index 0000000..07b6867 --- /dev/null +++ b/04_day/binder_4/ProcessState.cpp @@ -0,0 +1,54 @@ +#if 1 +#include +class ProcessState +{ + static ProcessState *gProcess; + ProcessState() + { + printf("fd=open(\"/dev/binder\", O_RDWR)\n"); + } + public: + static ProcessState *self() + { + if( gProcess == 0 ) + gProcess = new ProcessState; + return gProcess; + } + ~ProcessState() + { + printf("close(fd)\n"); + } +}; +ProcessState *ProcessState::gProcess = 0; + +int main() +{ + ProcessState *p1 = ProcessState::self(); + ProcessState *p2 = ProcessState::self(); + //ProcessState process; + return 0; +} +#endif + +#if 0 +#include +class ProcessState +{ + public: + ProcessState() + { + printf("fd=open(\"/dev/binder\", O_RDWR)\n"); + } + ~ProcessState() + { + printf("close(fd)\n"); + } +}; + +int main() +{ + ProcessState p1; + ProcessState p2; + return 0; +} +#endif diff --git a/04_day/binder_4/my_client.cpp b/04_day/binder_4/my_client.cpp new file mode 100644 index 0000000..c651d64 --- /dev/null +++ b/04_day/binder_4/my_client.cpp @@ -0,0 +1,23 @@ + +#include +#include +#include +#include +#include +#include "ILedService.h" + +using namespace android; + +int main() +{ + sp proc(ProcessState::self()); + sp sm(defaultServiceManager()); + sp binder = sm->getService( String16("led.service") ); + sp led = interface_cast( binder ); + led->ledOn(); + + return 0; +} + + + diff --git a/04_day/binder_4/my_server.cpp b/04_day/binder_4/my_server.cpp new file mode 100644 index 0000000..d2481ff --- /dev/null +++ b/04_day/binder_4/my_server.cpp @@ -0,0 +1,38 @@ + +#include +#include +#include +#include +#include + +using namespace android; + +class LedService : public BBinder +{ + public: + status_t onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) + { + switch (code) { + case 1: + printf("LedService::LED_ON\n"); + return NO_ERROR; + + default: + return BBinder::onTransact(code, data, reply, flags); + } + } +}; + +int main() +{ + sp proc(ProcessState::self()); + sp sm(defaultServiceManager()); + sm->addService( String16("led.service"), new LedService ); + IPCThreadState::self()->joinThreadPool(); + + return 0; +} + + + diff --git a/04_day/binder_5/Android.bp b/04_day/binder_5/Android.bp new file mode 100644 index 0000000..6ea477f --- /dev/null +++ b/04_day/binder_5/Android.bp @@ -0,0 +1,18 @@ +cc_binary { + name: "my_server_cpp_3", + shared_libs: ["liblog", "libutils", "libbinder"], + srcs: [ + "my_server.cpp", + "ILedService.cpp", + "LedService.cpp", + ], +} + +cc_binary { + name: "my_client_cpp_3", + shared_libs: ["liblog", "libutils", "libbinder"], + srcs: [ + "my_client.cpp", + "ILedService.cpp", + ], +} diff --git a/04_day/binder_5/ILedService.cpp b/04_day/binder_5/ILedService.cpp new file mode 100644 index 0000000..d8c6244 --- /dev/null +++ b/04_day/binder_5/ILedService.cpp @@ -0,0 +1,46 @@ +#define LOG_TAG "LedService" + +#include "ILedService.h" + +#include +#include +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class BpLedService : public BpInterface +{ +public: + explicit BpLedService(const sp& impl) + : BpInterface(impl) + { + } + + virtual void ledOn(void) + { + printf("BpLedService::ledOn()\n"); + Parcel data, reply; + remote()->transact(LED_ON, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(LedService, "android.os.ILedService"); + +// ---------------------------------------------------------------------- + +status_t BnLedService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + case LED_ON: { + ledOn(); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} +// ---------------------------------------------------------------------- +}; // namespace android diff --git a/04_day/binder_5/ILedService.h b/04_day/binder_5/ILedService.h new file mode 100644 index 0000000..1def502 --- /dev/null +++ b/04_day/binder_5/ILedService.h @@ -0,0 +1,41 @@ +#ifndef ANDROID_ILED_SERVICE_H +#define ANDROID_ILED_SERVICE_H + +#include +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class ILedService : public IInterface +{ +public: + DECLARE_META_INTERFACE(LedService) + + virtual void ledOn() = 0; + + enum { + LED_ON = IBinder::FIRST_CALL_TRANSACTION + }; +}; + +// ---------------------------------------------------------------------- + +class BnLedService : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_ISERVICE_MANAGER_H + + + + diff --git a/04_day/binder_5/LedService.cpp b/04_day/binder_5/LedService.cpp new file mode 100644 index 0000000..a62c39f --- /dev/null +++ b/04_day/binder_5/LedService.cpp @@ -0,0 +1,10 @@ +#include "LedService.h" +#include + +namespace android +{ + void LedService::ledOn(void) + { + printf("LedService::ledOn()\n"); + } +}; diff --git a/04_day/binder_5/LedService.h b/04_day/binder_5/LedService.h new file mode 100644 index 0000000..27508ba --- /dev/null +++ b/04_day/binder_5/LedService.h @@ -0,0 +1,13 @@ +#ifndef ANDROID_LED_SERVICE_H +#define ANDROID_LED_SERVICE_H +#include "ILedService.h" + +namespace android { + class LedService : public BnLedService + { + public : + void ledOn(void); + }; +}; + +#endif diff --git a/04_day/binder_5/ProcessState.cpp b/04_day/binder_5/ProcessState.cpp new file mode 100644 index 0000000..07b6867 --- /dev/null +++ b/04_day/binder_5/ProcessState.cpp @@ -0,0 +1,54 @@ +#if 1 +#include +class ProcessState +{ + static ProcessState *gProcess; + ProcessState() + { + printf("fd=open(\"/dev/binder\", O_RDWR)\n"); + } + public: + static ProcessState *self() + { + if( gProcess == 0 ) + gProcess = new ProcessState; + return gProcess; + } + ~ProcessState() + { + printf("close(fd)\n"); + } +}; +ProcessState *ProcessState::gProcess = 0; + +int main() +{ + ProcessState *p1 = ProcessState::self(); + ProcessState *p2 = ProcessState::self(); + //ProcessState process; + return 0; +} +#endif + +#if 0 +#include +class ProcessState +{ + public: + ProcessState() + { + printf("fd=open(\"/dev/binder\", O_RDWR)\n"); + } + ~ProcessState() + { + printf("close(fd)\n"); + } +}; + +int main() +{ + ProcessState p1; + ProcessState p2; + return 0; +} +#endif diff --git a/04_day/binder_5/my_client.cpp b/04_day/binder_5/my_client.cpp new file mode 100644 index 0000000..c651d64 --- /dev/null +++ b/04_day/binder_5/my_client.cpp @@ -0,0 +1,23 @@ + +#include +#include +#include +#include +#include +#include "ILedService.h" + +using namespace android; + +int main() +{ + sp proc(ProcessState::self()); + sp sm(defaultServiceManager()); + sp binder = sm->getService( String16("led.service") ); + sp led = interface_cast( binder ); + led->ledOn(); + + return 0; +} + + + diff --git a/04_day/binder_5/my_server.cpp b/04_day/binder_5/my_server.cpp new file mode 100644 index 0000000..18816ac --- /dev/null +++ b/04_day/binder_5/my_server.cpp @@ -0,0 +1,22 @@ + +#include +#include +#include +#include +#include +#include "LedService.h" + +using namespace android; + +int main() +{ + sp proc(ProcessState::self()); + sp sm(defaultServiceManager()); + sm->addService( String16("led.service"), new LedService ); + IPCThreadState::self()->joinThreadPool(); + + return 0; +} + + + diff --git a/04_day/binder_6/Android.bp b/04_day/binder_6/Android.bp new file mode 100644 index 0000000..b67485e --- /dev/null +++ b/04_day/binder_6/Android.bp @@ -0,0 +1,21 @@ +cc_binary { + name: "my_server_cpp_4", + shared_libs: ["liblog", "libutils", "libbinder"], + srcs: [ + "my_server.cpp", + "ILedService.cpp", + "LedService.cpp", + "ILedClient.cpp", + ], +} + +cc_binary { + name: "my_client_cpp_4", + shared_libs: ["liblog", "libutils", "libbinder"], + srcs: [ + "my_client.cpp", + "ILedService.cpp", + "ILedClient.cpp", + "Led.cpp", + ], +} diff --git a/04_day/binder_6/ILedClient.cpp b/04_day/binder_6/ILedClient.cpp new file mode 100644 index 0000000..cc498da --- /dev/null +++ b/04_day/binder_6/ILedClient.cpp @@ -0,0 +1,49 @@ +#define LOG_TAG "LedClient" + +#include "ILedClient.h" + +#include +#include +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class BpLedClient : public BpInterface +{ +public: + explicit BpLedClient(const sp& impl) + : BpInterface(impl) + { + } + + virtual void dataCallback(int ratio) + { + printf("BpLedClient::dataCallback()\n"); + Parcel data, reply; + data.writeInt32(ratio); + remote()->transact(DATA_CALLBACK, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(LedClient, "android.os.ILedClient"); + +// ---------------------------------------------------------------------- + +status_t BnLedClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + case DATA_CALLBACK: { + int temp; + temp = data.readInt32(); + dataCallback(temp); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} +// ---------------------------------------------------------------------- +}; // namespace android diff --git a/04_day/binder_6/ILedClient.h b/04_day/binder_6/ILedClient.h new file mode 100644 index 0000000..bf63ad0 --- /dev/null +++ b/04_day/binder_6/ILedClient.h @@ -0,0 +1,41 @@ +#ifndef ANDROID_ILED_CLIENT_H +#define ANDROID_ILED_CLIENT_H + +#include +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class ILedClient : public IInterface +{ +public: + DECLARE_META_INTERFACE(LedClient) + + virtual void dataCallback (int ratio) = 0; + + enum { + DATA_CALLBACK = IBinder::FIRST_CALL_TRANSACTION + }; +}; + +// ---------------------------------------------------------------------- + +class BnLedClient : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_ISERVICE_MANAGER_H + + + + diff --git a/04_day/binder_6/ILedService.cpp b/04_day/binder_6/ILedService.cpp new file mode 100644 index 0000000..5b5adee --- /dev/null +++ b/04_day/binder_6/ILedService.cpp @@ -0,0 +1,49 @@ +#define LOG_TAG "LedService" + +#include "ILedService.h" + +#include +#include +#include + +namespace android { + +// ---------------------------------------------------------------------- + +class BpLedService : public BpInterface +{ +public: + explicit BpLedService(const sp& impl) + : BpInterface(impl) + { + } + + virtual void connect(sp& client) + { + printf("BpLedService::ledOn()\n"); + Parcel data, reply; + data.writeStrongBinder(ILedClient::asBinder(client)); + remote()->transact(CONNECT, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(LedService, "android.os.ILedService"); + +// ---------------------------------------------------------------------- + +status_t BnLedService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + case CONNECT: { + sp client; + data.readStrongBinder(&client); + connect(client); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} +// ---------------------------------------------------------------------- +}; // namespace android diff --git a/04_day/binder_6/ILedService.h b/04_day/binder_6/ILedService.h new file mode 100644 index 0000000..9a67220 --- /dev/null +++ b/04_day/binder_6/ILedService.h @@ -0,0 +1,42 @@ +#ifndef ANDROID_ILED_SERVICE_H +#define ANDROID_ILED_SERVICE_H + +#include +#include +#include "ILedClient.h" + +namespace android { + +// ---------------------------------------------------------------------- + +class ILedService : public IInterface +{ +public: + DECLARE_META_INTERFACE(LedService) + + virtual void connect(sp& client) = 0; + + enum { + CONNECT = IBinder::FIRST_CALL_TRANSACTION + }; +}; + +// ---------------------------------------------------------------------- + +class BnLedService : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_ISERVICE_MANAGER_H + + + + diff --git a/04_day/binder_6/Led.cpp b/04_day/binder_6/Led.cpp new file mode 100644 index 0000000..994251a --- /dev/null +++ b/04_day/binder_6/Led.cpp @@ -0,0 +1,10 @@ +#include "Led.h" +#include + +namespace android +{ + void Led::dataCallback(int ratio) + { + printf("Led::dataCallback(%d)\n", ratio); + } +}; diff --git a/04_day/binder_6/Led.h b/04_day/binder_6/Led.h new file mode 100644 index 0000000..766ecb8 --- /dev/null +++ b/04_day/binder_6/Led.h @@ -0,0 +1,13 @@ +#ifndef ANDROID_LED_H +#define ANDROID_LED_H +#include "ILedClient.h" + +namespace android { + class Led : public BnLedClient + { + public : + void dataCallback(int ratio); + }; +}; + +#endif diff --git a/04_day/binder_6/LedService.cpp b/04_day/binder_6/LedService.cpp new file mode 100644 index 0000000..55b4ca0 --- /dev/null +++ b/04_day/binder_6/LedService.cpp @@ -0,0 +1,11 @@ +#include "LedService.h" +#include + +namespace android +{ + void LedService::connect(sp& client) + { + printf("LedService::ledOn()\n"); + client->dataCallback(222); + } +}; diff --git a/04_day/binder_6/LedService.h b/04_day/binder_6/LedService.h new file mode 100644 index 0000000..1bb5d4a --- /dev/null +++ b/04_day/binder_6/LedService.h @@ -0,0 +1,13 @@ +#ifndef ANDROID_LED_SERVICE_H +#define ANDROID_LED_SERVICE_H +#include "ILedService.h" + +namespace android { + class LedService : public BnLedService + { + public : + void connect(sp& client); + }; +}; + +#endif diff --git a/04_day/binder_6/ProcessState.cpp b/04_day/binder_6/ProcessState.cpp new file mode 100644 index 0000000..07b6867 --- /dev/null +++ b/04_day/binder_6/ProcessState.cpp @@ -0,0 +1,54 @@ +#if 1 +#include +class ProcessState +{ + static ProcessState *gProcess; + ProcessState() + { + printf("fd=open(\"/dev/binder\", O_RDWR)\n"); + } + public: + static ProcessState *self() + { + if( gProcess == 0 ) + gProcess = new ProcessState; + return gProcess; + } + ~ProcessState() + { + printf("close(fd)\n"); + } +}; +ProcessState *ProcessState::gProcess = 0; + +int main() +{ + ProcessState *p1 = ProcessState::self(); + ProcessState *p2 = ProcessState::self(); + //ProcessState process; + return 0; +} +#endif + +#if 0 +#include +class ProcessState +{ + public: + ProcessState() + { + printf("fd=open(\"/dev/binder\", O_RDWR)\n"); + } + ~ProcessState() + { + printf("close(fd)\n"); + } +}; + +int main() +{ + ProcessState p1; + ProcessState p2; + return 0; +} +#endif diff --git a/04_day/binder_6/a.out b/04_day/binder_6/a.out new file mode 100644 index 0000000000000000000000000000000000000000..5f7720d4553294d8dcf5810a693a4c4356686717 GIT binary patch literal 8512 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 literal 0 HcmV?d00001 diff --git a/04_day/binder_6/my_client.cpp b/04_day/binder_6/my_client.cpp new file mode 100644 index 0000000..1c98b77 --- /dev/null +++ b/04_day/binder_6/my_client.cpp @@ -0,0 +1,27 @@ + +#include +#include +#include +#include +#include +#include "ILedService.h" +#include "Led.h" + +using namespace android; + +int main() +{ + sp proc(ProcessState::self()); + sp sm(defaultServiceManager()); + sp binder = sm->getService( String16("led.service") ); + sp led = interface_cast( binder ); + sp client = new Led; + led->connect( client ); + IPCThreadState::self()->joinThreadPool(); + + + return 0; +} + + + diff --git a/04_day/binder_6/my_server.cpp b/04_day/binder_6/my_server.cpp new file mode 100644 index 0000000..18816ac --- /dev/null +++ b/04_day/binder_6/my_server.cpp @@ -0,0 +1,22 @@ + +#include +#include +#include +#include +#include +#include "LedService.h" + +using namespace android; + +int main() +{ + sp proc(ProcessState::self()); + sp sm(defaultServiceManager()); + sm->addService( String16("led.service"), new LedService ); + IPCThreadState::self()->joinThreadPool(); + + return 0; +} + + + diff --git a/04_day/binder_6/thread.cpp b/04_day/binder_6/thread.cpp new file mode 100644 index 0000000..a0813ed --- /dev/null +++ b/04_day/binder_6/thread.cpp @@ -0,0 +1,43 @@ +#if 1 +#include +#include +#include +int global=6; +void *foo(void *data) +{ + printf("child , global=%d, local=%d\n", ++global, ++*(int*)data); + return 0; +} +int main() +{ + int local=10; + pthread_t thread; + + pthread_create(&thread, 0, foo, &local ); + //foo(&local); + pthread_join( thread, 0 ); + printf("parent , global=%d, local=%d\n", ++global, local); + return 0; +} +#endif + +#if 0 +#include +#include +#include +#include +int global=6; +int main() +{ + pid_t pid; + pid = fork(); + if( pid == 0 ) + { + printf("child, global=%d\n", ++global); + exit(0); + } + wait(0); + printf("parent, global=%d\n", global); + return 0; +} +#endif diff --git a/04_day/sp/Android.bp b/04_day/sp/Android.bp new file mode 100644 index 0000000..5250796 --- /dev/null +++ b/04_day/sp/Android.bp @@ -0,0 +1,7 @@ +cc_binary { + name: "my_wp", + shared_libs: ["liblog", "libutils"], + srcs: [ + "wp_1.cpp", + ], +} diff --git a/04_day/sp/a.out b/04_day/sp/a.out new file mode 100644 index 0000000000000000000000000000000000000000..a4c8bd2ad8bcdd16124b8ceae13c682a3e9f0558 GIT binary patch literal 14120 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 + +class RefBase +{ + int mRefs; + public: + RefBase():mRefs(0) { printf("RefBase::RefBase()\n"); } + virtual ~RefBase() { printf("RefBase::~RefBase()\n"); } + void incStrong() { + printf("RefBase::incStrong() : mRefs=%d\n", ++mRefs); + } + void decStrong() + { + --mRefs; + printf("RefBase::decStrong() : mRefs=%d\n", mRefs); + if( mRefs == 0 ) + delete this; + } +}; +class AAA : public virtual RefBase +{ + 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(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 +{ + 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 diff --git a/04_day/sp/sp_1.cpp b/04_day/sp/sp_1.cpp new file mode 100644 index 0000000..ca1ff55 --- /dev/null +++ b/04_day/sp/sp_1.cpp @@ -0,0 +1,82 @@ +#if 1 +#include +#include +#include + +using namespace android; + +class AAA; +class BBB; + +class AAA : public virtual RefBase +{ + public: + wp pb; + AAA(){ printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; +class BBB : public virtual RefBase +{ + public: + wp pa; + BBB(){ printf("BBB::BBB()\n"); } + ~BBB() { printf("BBB::~BBB()\n"); } + void foo() { printf("BBB::foo()\n"); } +}; + +int main() +{ + { + sp p1 = new AAA; + sp p2 = new BBB; + p1->pb = p2; + p2->pa = p1; + } + return 0; +} +#endif + + + +#if 0 +#include +#include +#include + +using namespace android; + +class AAA; +class BBB; + +class AAA : public virtual RefBase +{ + public: + sp pb; + AAA(){ printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; +class BBB : public virtual RefBase +{ + public: + sp pa; + BBB(){ printf("BBB::BBB()\n"); } + ~BBB() { printf("BBB::~BBB()\n"); } + void foo() { printf("BBB::foo()\n"); } +}; + +int main() +{ + { + sp p1 = new AAA; + sp p2 = new BBB; + p1->pb = p2; + p2->pa = p1; + } + return 0; +} +#endif + + + diff --git a/04_day/sp/wp_1.cpp b/04_day/sp/wp_1.cpp new file mode 100644 index 0000000..84e0156 --- /dev/null +++ b/04_day/sp/wp_1.cpp @@ -0,0 +1,119 @@ +#if 1 +#include +#include +#include + +using namespace android; + +class AAA : public virtual RefBase +{ + int data; + public: + AAA(){ printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() // void foo( AAA *this ) + { + data = 10; // this->data = 10; => (*0).data = 10; + printf("AAA::foo()\n"); + } +}; + +int main() +{ + //((AAA*)0)->foo(); // AAA::foo(0); + { + wp p1 = new AAA; + { + sp p2 = p1.promote(); + p2->foo(); + } + printf("step 1.\n"); + if( p1.promote() != 0 ) + p1.promote()->foo(); + else + printf("객체는 이미 소멸됨\n"); + } + printf("step 2.\n"); + return 0; +} +#endif + +#if 0 +#include +#include +#include + +using namespace android; + +class AAA : public virtual RefBase +{ + public: + AAA(){ printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; + +int main() +{ + { + wp p1 = new AAA; + sp p2 = p1.promote(); + p2->foo(); + } + return 0; +} +#endif +#if 0 +#include +#include +#include + +using namespace android; + +class AAA : public virtual RefBase +{ + public: + AAA(){ printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; + +int main() +{ + { + sp p1 = new AAA; + wp p2 = p1; + p1->foo(); + } + return 0; +} +#endif + + +#if 0 +#include +#include +#include + +using namespace android; + +class AAA : public virtual RefBase +{ + public: + AAA(){ printf("AAA::AAA()\n"); } + ~AAA() { printf("AAA::~AAA()\n"); } + void foo() { printf("AAA::foo()\n"); } +}; + +int main() +{ + { + wp pa = new AAA; + pa.promote()->foo(); + } + return 0; +} +#endif + + + diff --git a/04_day/thread/.Thread.cpp.swp b/04_day/thread/.Thread.cpp.swp new file mode 100644 index 0000000000000000000000000000000000000000..b289f5c5603bd9d55fa2791d9d6d559455e2cd93 GIT binary patch literal 16384 zcmeI&du&rx0LSqIY+{iCK{5P+=4^ALo!i=h=(4c|P-75LRFH@yabcJc=kXN|Vn6nx6Fbm>l~{r}9>o2a zfl(;N5Pa_u;&Xg}-PnarY{N@<5*;v+LJJjKa2!W)2>b93-o{qEiVawScC;acAR2K8M&QgfLY%^J{D@9$ z!Dg(6i6~mJ0P}DUCcukI+=OvBT`a^&9Kt8~2nX>zp21UChB=slTQL$v7>wVF=rf$d z863tz?7?nq!DehiE9PS!rl0|S)Swa)CFo*~9mdx=%l~mj8 zry;{Mq)(JbAl=WI-yp=iS16p;Z@9*&2ik)Fr%as-dHS8r9)XYJo7 zWs^EsqvY6BM=my^aj#GK{WX{PXSK5TrnwFC$(-6>Op`?6MtKdxs8y};HA?CCORHs- zZ1lNJojP@DLxWX9wYAcEsah;NJe8E>ncuH=qw41D#x3Qwc4d{wmL9mE*sq5%;mHn# z>|vep;PEWyZL7<=gR|P1Evc$iWwu4rKEaU6ER02i4cURmoBfQr;K;E;%?&skZlPQ+ zYd)TI*yML_PHpeL8y# zsV0q8gh|@n0Uotk?Vx)R=zm`n9`W|#Qq#OBp=K%-b2p?i_G^2!QG-JLQjako4=;0; zAXS@zndK`uuo}AVqG#2{S@^1DK&px@cc!3S)BN&5>Sl($veK?4AE{RBP|uHAZL&X^ zvvM*cVwuI^rn-PyN3*lXn!ol!s*au8+XYrscdl4nW$%!kx$WtF5g&k+*zK|ZUKh4l zeW)g0-U#TW8`I%fq^8;GHr0>rz*Uf9_Isu>5aHdr0PfuU0c(t+7%O zVr00ltQ8?|5HVizmj!XvjgOh_c3?dwd3L7$gR!_LI&KwYgS6vwPksKz`9!w<_N-|c zh?V9_57VX5l$kMNJ->;X)Olfc++F#lsLbt8b#CfOCnwtjtl3%Tov#+RP%q=oS+^rb zEFD&}+&wpRKi1G-ckF$MMAGYXXJ}L3^L1e&5p!x{eOAq1Uw3@!d(K_f|H<*0Nk`+Y zGHxsmr;|o7ES=xWH*&(7J!j9D(OBC5u$fB4TW9gTZH80%=kIm_JKp?v^3Lq*gu4EJ zlxt>n{jIM5E1i23U0lx}$1%K*eRvByu?}mo2D5NC?nDK~pa|+-z_0iTr*IM{a1@_m zKel2E*5O$^jdm +#include +#include + +using namespace android; +//-------------------------------------------------------- +class MyThread : public Thread +{ + int volume; +public: + bool threadLoop(void) + { + volume=100; + printf("MyThread::threadLoop(), volume=%d\n", volume); + return false; + } +}; +int main() +{ + sp thread = new MyThread; + thread->run("MyThread"); + thread->join(); + return 0; +} +#endif +#if 0 +#include +#include + +class Thread +{ + pthread_t thread; +public: + virtual void foo(void) = 0; + static void * _foo(void *data ) + { + Thread *self = (Thread*)data; + self->foo(); + return 0; + } + void run() + { + pthread_create( &thread, 0, _foo, this ); + } + void join() + { + pthread_join( thread, 0 ); + } +}; +//-------------------------------------------------------- +class MyThread : public Thread +{ + int volume; +public: + void foo(void) + { + volume=100; + printf("foo(), volume=%d\n", volume); + } +}; +int main() +{ + Thread *thread = new MyThread; + thread->run(); + thread->join(); + return 0; +} +#endif +#if 0 +#include +#include + +class Thread +{ + pthread_t thread; + int volume; +public: + void foo(void) + { + volume=100; + printf("foo(), volume=%d\n", volume); + } + static void * _foo(void *data ) + { + Thread *self = (Thread*)data; + self->foo(); + return 0; + } + void run() + { + pthread_create( &thread, 0, _foo, this ); + } + void join() + { + pthread_join( thread, 0 ); + } +}; +//-------------------------------------------------------- +int main() +{ + Thread *thread = new Thread; + thread->run(); + thread->join(); + return 0; +} +#endif +#if 0 +#include +#include + +class Thread +{ + pthread_t thread; + int volume; +public: + static void * foo(void *data ) + { + printf("foo()\n"); + volume=100; + return 0; + } + void run() + { + pthread_create( &thread, 0, foo, 0 ); + } + void join() + { + pthread_join( thread, 0 ); + } +}; +//-------------------------------------------------------- +int main() +{ + Thread *thread = new Thread; + thread->run(); + thread->join(); + return 0; +} +#endif + +#if 0 +#include +#include +class AAA +{ + int data; + public: + + void set_data( int _data ) + { + data = _data; + } + + static void foo(void) // AAA::foo() + { + set_data(10); // set_data(this, 10); + printf("AAA::foo()\n"); + } +}; + +//-------------------------------------------------------- +int main() +{ + void (*p)() = &AAA::foo; + (*p)(); // (*p)() + return 0; +} +#endif +#if 0 +#include +#include +class AAA +{ + public: + + void foo(void) // AAA::foo(AAA *this) + { + printf("AAA::foo()\n"); + } +}; + +//-------------------------------------------------------- +int main() +{ + //AAA aaa; + //aaa.foo(); // AAA::foo(&aaa); + AAA aaa; + void (AAA::*p)() = &AAA::foo; + (aaa.*p)(); // (*p)(&aaa) + return 0; +} +#endif + + +#if 0 +#include +#include +void foo(void) +{ + printf("foo()\n"); +} + +//-------------------------------------------------------- +int main() +{ + void (*p)(void) = foo; + p(); + return 0; +} +#endif +#if 0 +#include +#include +void * foo(void *data ) +{ + printf("foo()\n"); + return 0; +} + +class Thread +{ + pthread_t thread; +public: + void run() + { + pthread_create( &thread, 0, foo, 0 ); + } + void join() + { + pthread_join( thread, 0 ); + } +}; +//-------------------------------------------------------- +int main() +{ + Thread *thread = new Thread; + thread->run(); + thread->join(); + return 0; +} +#endif + + + +#if 0 +#include +#include +void * foo(void *data ) +{ + printf("foo()\n"); + return 0; +} +int main() +{ + pthread_t thread; + pthread_create( &thread, 0, foo, 0 ); + pthread_join( thread, 0 ); + return 0; +} +#endif diff --git a/04_day/thread/a.out b/04_day/thread/a.out new file mode 100644 index 0000000000000000000000000000000000000000..22bb185e6c0c5831d5803f86dcc9afb2b00f6ee3 GIT binary patch literal 13400 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 literal 0 HcmV?d00001