花了一个上午的时间把这篇文章翻译完,确实写的很透彻,但美中不足的地方是没有插图,不能直观的了解Binder机制,说实话我自己对binder也理解的很浅显,特别是到binder kernel driver哪块,还要等我先学习linux驱动再来看一遍吧,等以后看懂了再自己绘图应该更有助于理解。
------------------------------------------------------------------------荤勾线-----------------------------------------------------------------------------------------------------
我将利用IAudioFlinger::setMode这个API作为一个简单的场景,来展示Android IPC系统是如何工作的,AudioFlinger是多媒体服务系统中的一个服务。
运行Service Manager
service_manager 是为其它进程提供“服务”管理的“服务”。所以,它必须比于其它任何服务先运行。
- int main(int argc, char **argv)
- {
- struct binder_state *bs;
- void *svcmgr = BINDER_SERVICE_MANAGER;
- bs = binder_open(128*1024);
- if (binder_become_context_manager(bs)) {
- LOGE("cannot become context manager (%s)/n", strerror(errno));
- return -1;
- }
- svcmgr_handle = svcmgr;
- binder_loop(bs, svcmgr_handler);
- return 0;
- }
首先打开“/dev/binder”驱动,且调用BINDER_SET_CONTEXT_MGR这个ioctl,让内核驱动知道该设备是作为管理者(manager)的角色。然后进入一个循环,等待来自其它进程的数据。
- void binder_loop(struct binder_state *bs, binder_handler func)
- {
- int res;
- struct binder_write_read bwr;
- unsigned readbuf[32];
- bwr.write_size = 0;
- bwr.write_consumed = 0;
- bwr.write_buffer = 0;
- readbuf[0] = BC_ENTER_LOOPER;
- binder_write(bs, readbuf, sizeof(unsigned));
- for (;;) {
- bwr.read_size = sizeof(readbuf);
- bwr.read_consumed = 0;
- bwr.read_buffer = (unsigned) readbuf;
- res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
- if (res < 0) {
- LOGE("binder_loop: ioctl failed (%s)/n", strerror(errno));
- break;
- }
- res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
- if (res == 0) {
- LOGE("binder_loop: unexpected reply?!/n");
- break;
- }
- if (res < 0) {
- LOGE("binder_loop: io error %d %s/n", res, strerror(errno));
- break;
- }
- }
- }
注意BINDER_SERVICE_MANAGER.
- /* the one magic object */
- #define BINDER_SERVICE_MANAGER ((void*) 0)
- sp<IServiceManager> defaultServiceManager()
- {
- if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
- {
- AutoMutex _l(gDefaultServiceManagerLock);
- if (gDefaultServiceManager == NULL) {
- gDefaultServiceManager = interface_cast<IServiceManager>(
- ProcessState::self()->getContextObject(NULL));
- }
- }
- return gDefaultServiceManager;
- }
- ProcessState::ProcessState()
- : mDriverFD(open_driver())
- sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
- {
- if (supportsProcesses()) {
- return getStrongProxyForHandle(0);
- } else {
- return getContextObject(String16("default"), caller);
- }
- }
- sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
- {
- sp<IBinder> result;
- AutoMutex _l(mLock);
- handle_entry* e = lookupHandleLocked(handle);
- if (e != NULL) {
- // We need to create a new BpBinder if there isn't currently one, OR we
- // are unable to acquire a weak reference on this current one. See comment
- // in getWeakProxyForHandle() for more info about this.
- IBinder* b = e->binder;
- if (b == NULL || !e->refs->attemptIncWeak(this)) {
- b = new BpBinder(handle);
- e->binder = b;
- if (b) e->refs = b->getWeakRefs();
- result = b;
- } else {
- // This little bit of nastyness is to allow us to add a primary
- // reference to the remote proxy when this team doesn't have one
- // but another team is sending the handle to us.
- result.force_set(b);
- e->refs->decWeak(this);
- }
- }
- return result;
- }
- BpBinder::BpBinder(int32_t handle)
- : mHandle(handle)
- , mAlive(1)
- , mObitsSent(0)
- , mObituaries(NULL)
- {
- LOGV("Creating BpBinder %p handle %d/n", this, mHandle);
- extendObjectLifetime(OBJECT_LIFETIME_WEAK);
- IPCThreadState::self()->incWeakHandle(handle);
- }
- void IPCThreadState::incWeakHandle(int32_t handle)
- {
- LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)/n", handle);
- mOut.writeInt32(BC_INCREFS);
- mOut.writeInt32(handle);
- }
- inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
- {
- return IServiceManager::asInterface(obj);
- }
- class IServiceManager : public IInterface
- {
- public:
- DECLARE_META_INTERFACE(ServiceManager);
- /**
- * Retrieve an existing service, blocking for a few seconds
- * if it doesn't yet exist.
- */
- virtual sp<IBinder> getService( const String16& name) const = 0;
- /**
- * Retrieve an existing service, non-blocking.
- */
- virtual sp<IBinder> checkService( const String16& name) const = 0;
- /**
- * Register a service.
- */
- virtual status_t addService( const String16& name,
- const sp<IBinder>& service) = 0;
- /**
- * Return list of all existing services.
- */
- virtual Vector<String16> listServices() = 0;
- enum {
- GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- CHECK_SERVICE_TRANSACTION,
- ADD_SERVICE_TRANSACTION,
- LIST_SERVICES_TRANSACTION,
- };
- };
- static const String16 descriptor;
- static sp<IServiceManager> asInterface(const sp<IBinder>& obj);
- virtual String16 getInterfaceDescriptor() const;
- const String16 IServiceManager::descriptor(NAME);
- String16 IServiceManager::getInterfaceDescriptor() const {
- return IServiceManager::descriptor;
- }
- sp<IServiceManager> IServiceManager::asInterface(const sp<IBinder>& obj)
- {
- sp<IServiceManager> intr;
- if (obj != NULL) {
- intr = static_cast<IServiceManager*>(
- obj->queryLocalInterface(
- IServiceManager::descriptor).get());
- if (intr == NULL) {
- intr = new BpServiceManager(obj);
- }
- }
- return intr;
- }
- int main(int argc, char** argv)
- {
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- LOGI("ServiceManager: %p", sm.get());
- AudioFlinger::instantiate();
- MediaPlayerService::instantiate();
- CameraService::instantiate();
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- }
- void AudioFlinger::instantiate() {
- defaultServiceManager()->addService(
- String16("media.audio_flinger"), new AudioFlinger());
- }
- class BnAudioFlinger : public BnInterface<IAudioFlinger>
- {
- public:
- virtual status_t onTransact( uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
- };
- template<typename INTERFACE>class BnInterface : public INTERFACE, public BBinder
- {
- public:
- virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
- virtual String16 getInterfaceDescriptor() const;
- protected:
- virtual IBinder* onAsBinder();
- };
- template<typename INTERFACE>
- IBinder* BnInterface<INTERFACE>::onAsBinder()
- {
- return this;
- }
- status_t BBinder::transact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- data.setDataPosition(0);
- status_t err = NO_ERROR;
- switch (code) {
- case PING_TRANSACTION:
- reply->writeInt32(pingBinder());
- break;
- default:
- err = onTransact(code, data, reply, flags);
- break;
- }
- if (reply != NULL) {
- reply->setDataPosition(0);
- }
- return err;
- }
- status_t BnAudioFlinger::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- switch(code) {
- case SET_MODE: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- int mode = data.readInt32();
- reply->writeInt32( setMode(mode) );
- return NO_ERROR;
- } break;
- void IPCThreadState::joinThreadPool(bool isMain)
- {
- mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
- status_t result;
- do {
- int32_t cmd;
- result = talkWithDriver();
- if (result >= NO_ERROR) {
- size_t IN = mIn.dataAvail();
- if (IN < sizeof(int32_t)) continue;
- cmd = mIn.readInt32();
- result = executeCommand(cmd);
- }
- // Let this thread exit the thread pool if it is no longer
- // needed and it is not the main process thread.
- if(result == TIMED_OUT && !isMain) {
- break;
- }
- } while (result != -ECONNREFUSED && result != -EBADF);
- mOut.writeInt32(BC_EXIT_LOOPER);
- talkWithDriver(false);
- }
- virtual status_t addService(const String16& name, const sp<IBinder>& service){
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- data.writeStrongBinder(service);
- status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
- return err == NO_ERROR ? reply.readInt32() : err;
- }
- status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
- {
- return flatten_binder(ProcessState::self(), val, this);
- }
- status_t flatten_binder(const sp<ProcessState>& proc,
- const sp<IBinder>& binder, Parcel* out)
- {
- flat_binder_object obj;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (binder != NULL) {
- IBinder *local = binder->localBinder();
- if (!local) {
- BpBinder *proxy = binder->remoteBinder();
- if (proxy == NULL) {
- LOGE("null proxy");
- }
- const int32_t handle = proxy ? proxy->handle() : 0;
- obj.type = BINDER_TYPE_HANDLE;
- obj.handle = handle;
- obj.cookie = NULL;
- } else {
- obj.type = BINDER_TYPE_BINDER;
- obj.binder = local->getWeakRefs();
- obj.cookie = local;
- }
- }
- return finish_flatten_binder(binder, obj, out);
- }
- status_t BpBinder::transact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- // Once a binder has died, it will never come back to life.
- if (mAlive) {
- status_t status = IPCThreadState::self()->transact(
- mHandle, code, data, reply, flags);
- if (status == DEAD_OBJECT) mAlive = 0;
- return status;
- }
- return DEAD_OBJECT;
- }
- status_t IPCThreadState::transact(int32_t handle,
- uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags)
- {
- status_t err = data.errorCheck();
- flags |= TF_ACCEPT_FDS;
- if (err == NO_ERROR) {
- LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
- (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
- err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
- }
- if (err != NO_ERROR) {
- if (reply) reply->setError(err);
- return (mLastError = err);
- }
- if ((flags & TF_ONE_WAY) == 0) {
- if (reply) {
- err = waitForResponse(reply);
- } else {
- Parcel fakeReply;
- err = waitForResponse(&fakeReply);
- }
- } else {
- err = waitForResponse(NULL, NULL);
- }
- return err;
- }
- status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
- int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
- {
- binder_transaction_data tr;
- tr.target.handle = handle;
- tr.code = code;
- tr.flags = binderFlags;
- const status_t err = data.errorCheck();
- if (err == NO_ERROR) {
- tr.data_size = data.ipcDataSize();
- tr.data.ptr.buffer = data.ipcData();
- tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
- tr.data.ptr.offsets = data.ipcObjects();
- } else if (statusBuffer) {
- tr.flags |= TF_STATUS_CODE;
- *statusBuffer = err;
- tr.data_size = sizeof(status_t);
- tr.data.ptr.buffer = statusBuffer;
- tr.offsets_size = 0;
- tr.data.ptr.offsets = NULL;
- } else {
- return (mLastError = err);
- }
- mOut.writeInt32(cmd);
- mOut.write(&tr, sizeof(tr));
- return NO_ERROR;
- }
- #if defined(HAVE_ANDROID_OS)
- if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
- err = NO_ERROR;
- else
- err = -errno;
- #else
- static int binder_open(struct inode *nodp, struct file *filp)
- {
- struct binder_proc *proc;
- proc = kzalloc(sizeof(*proc), GFP_KERNEL);
- if (proc == NULL)
- return -ENOMEM;
- get_task_struct(current);
- proc->tsk = current;
- INIT_LIST_HEAD(&proc->todo);
- init_waitqueue_head(&proc->wait);
- proc->default_priority = task_nice(current);
- mutex_lock(&binder_lock);
- binder_stats.obj_created[BINDER_STAT_PROC]++;
- hlist_add_head(&proc->proc_node, &binder_procs);
- proc->pid = current->group_leader->pid;
- INIT_LIST_HEAD(&proc->delivered_death);
- filp->private_data = proc;
- mutex_unlock(&binder_lock);
- if (binder_proc_dir_entry_proc) {
- char strbuf[11];
- snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
- create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc,
- binder_read_proc_proc, proc);
- }
- return 0;
- }
- case BINDER_WRITE_READ: {
- struct binder_write_read bwr;
- if (size != sizeof(struct binder_write_read)) {
- ret = -EINVAL;
- goto err;
- }
- if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
- ret = -EFAULT;
- goto err;
- }
- if (bwr.write_size > 0) {
- ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer,
- bwr.write_size, &bwr.write_consumed);
- if (ret < 0) {
- bwr.read_consumed = 0;
- if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
- ret = -EFAULT;
- goto err;
- }
- }
- if (bwr.read_size > 0) {
- ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer,
- bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
- if (!list_empty(&proc->todo))
- wake_up_interruptible(&proc->wait);
- if (ret < 0) {
- if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
- ret = -EFAULT;
- goto err;
- }
- }
- if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
- ret = -EFAULT;
- goto err;
- }
- break;
- }
- uint32_t cmd;
- void __user *ptr = buffer + *consumed;
- void __user *end = buffer + size;
- while (ptr < end && thread->return_error == BR_OK) {
- if (get_user(cmd, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
- binder_stats.bc[_IOC_NR(cmd)]++;
- proc->stats.bc[_IOC_NR(cmd)]++;
- thread->stats.bc[_IOC_NR(cmd)]++;
- }
- switch (cmd) {
- case ***:
- default:
- printk(KERN_ERR "binder: %d:%d unknown command %d/n", proc->pid,
- thread->pid, cmd);
- return -EINVAL;
- }
- *consumed = ptr - buffer;
- }
- case BC_INCREFS:
- case BC_ACQUIRE:
- case BC_RELEASE:
- case BC_DECREFS: {
- uint32_t target;
- struct binder_ref *ref;
- const char *debug_string;
- if (get_user(target, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (target == 0 && binder_context_mgr_node &&
- (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
- ref = binder_get_ref_for_node(proc,
- binder_context_mgr_node);
- } else
- ref = binder_get_ref(proc, target);
- if (ref == NULL) {
- binder_user_error("binder: %d:%d refcou"
- "nt change on invalid ref %d/n",
- proc->pid, thread->pid, target);
- break;
- }
- switch (cmd) {
- case BC_INCREFS:
- debug_string = "IncRefs";
- binder_inc_ref(ref, 0, NULL);
- break;
- }
- break;
- case BC_TRANSACTION:
- case BC_REPLY: {
- struct binder_transaction_data tr;
- if (copy_from_user(&tr, ptr, sizeof(tr)))
- return -EFAULT;
- ptr += sizeof(tr);
- binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
- break;
- }
- fp = (struct flat_binder_object *)(t->buffer->data + *offp);
- switch (fp->type) {
- case BINDER_TYPE_BINDER:
- case BINDER_TYPE_WEAK_BINDER: {
- struct binder_ref *ref;
- struct binder_node *node = binder_get_node(proc, fp->binder);
- if (node == NULL) {
- node = binder_new_node(proc, fp->binder);
- if (node == NULL) {
- return_error = BR_FAILED_REPLY;
- goto err_binder_new_node_failed;
- }
- node->cookie = fp->cookie;
- }
- ref = binder_get_ref_for_node(target_proc, node);
- if (ref == NULL) {
- return_error = BR_FAILED_REPLY;
- goto err_binder_get_ref_for_node_failed;
- }
- if (fp->type == BINDER_TYPE_BINDER)
- fp->type = BINDER_TYPE_HANDLE;
- else
- fp->type = BINDER_TYPE_WEAK_HANDLE;
- fp->handle = ref->desc;
- binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);
- if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)
- printk(KERN_INFO " node %d u%p -> ref %d desc %d/n",
- node->debug_id, node->ptr, ref->debug_id, ref->desc);
- } break;
- } else {
- target_node = binder_context_mgr_node;
- if (target_node == NULL) {
- return_error = BR_DEAD_REPLY;
- goto err_no_context_mgr_node;
- }
- }
- e->to_node = target_node->debug_id;
- target_proc = target_node->proc;
- if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
- struct binder_transaction *tmp;
- tmp = thread->transaction_stack;
- while (tmp) {
- if (tmp->from && tmp->from->proc == target_proc)
- target_thread = tmp->from;
- tmp = tmp->from_parent;
- }
- }
- t->work.type = BINDER_WORK_TRANSACTION;
- list_add_tail(&t->work.entry, target_list);
- tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
- list_add_tail(&tcomplete->entry, &thread->todo);
- if (target_wait)
- wake_up_interruptible(target_wait);
- ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc,thread));
- tr.data_size = t->buffer->data_size;
- tr.offsets_size = t->buffer->offsets_size;
- tr.data.ptr.buffer = (void *)((void *)t->buffer->data + proc->user_buffer_offset);
- tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *));
- if (put_user(cmd, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (copy_to_user(ptr, &tr, sizeof(tr)))
- return -EFAULT;
- ptr += sizeof(tr);
- case BR_TRANSACTION: {
- if (func) {
- unsigned rdata[256/4];
- struct binder_io msg;
- struct binder_io reply;
- int res;
- bio_init(&reply, rdata, sizeof(rdata), 4);
- bio_init_from_txn(&msg, txn);
- res = func(bs, txn, &msg, &reply);
- binder_send_reply(bs, &reply, txn->data, res);
- }
- ptr += sizeof(*txn) / sizeof(uint32_t);
- break;
- }
- binder_parser will call svcmgr_handler to parse BR_TRANSACTION packet, which is the reverse
- process of BpServerManager. Here structure binder_txn actually is the same with structure
- binder_transaction_data. In our scenario, the transaction code is SVC_MGR_ADD_SERVICE.
- int svcmgr_handler(struct binder_state *bs,
- struct binder_txn *txn,
- struct binder_io *msg,
- struct binder_io *reply)
- {
- struct svcinfo *si;
- uint16_t *s;
- unsigned len;
- void *ptr;
- if (txn->target != svcmgr_handle)
- return -1;
- s = bio_get_string16(msg, &len);
- if ((len != (sizeof(svcmgr_id) / 2)) ||
- memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
- fprintf(stderr,"invalid id %s/n", str8(s));
- return -1;
- }
- switch(txn->code) {
- case SVC_MGR_ADD_SERVICE:
- s = bio_get_string16(msg, &len);
- ptr = bio_get_ref(msg);
- if (do_add_service(bs, s, len, ptr, txn->sender_euid))
- return -1;
- break;
- void *bio_get_ref(struct binder_io *bio)
- {
- struct binder_object *obj;
- obj = _bio_get_obj(bio);
- if (!obj)
- return 0;
- if (obj->type == BINDER_TYPE_HANDLE)
- return obj->pointer;
- return 0;
- }
- / establish binder interface to AudioFlinger service
- const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
- {
- Mutex::Autolock _l(gLock);
- if (gAudioFlinger.get() == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16("media.audio_flinger"));
- if (binder != 0)
- break;
- LOGW("AudioFlinger not published, waiting...");
- usleep(500000); // 0.5 s
- } while(true);
- gAudioFlinger = interface_cast<IAudioFlinger>(binder);
- }
- LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
- return gAudioFlinger;
- }
- IServiceManager::getService会调用BpServiceManager::getService.
- virtual sp<IBinder> getService(const String16& name) const
- {
- unsigned n;
- for (n = 0; n < 5; n++){
- sp<IBinder> svc = checkService(name);
- if (svc != NULL) return svc;
- LOGI("Waiting for sevice %s.../n", String8(name).string());
- sleep(1);
- }
- return NULL;
- }
- virtual sp<IBinder> checkService( const String16& name) const
- {
- Parcel data, reply;
- data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
- data.writeString16(name);
- remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
- return reply.readStrongBinder();
- }
- switch(txn->code) {
- case SVC_MGR_GET_SERVICE:
- case SVC_MGR_CHECK_SERVICE:
- s = bio_get_string16(msg, &len);
- ptr = do_find_service(bs, s, len);
- if (!ptr)
- break;
- bio_put_ref(reply, ptr);
- return 0;
- BpAudioFlinger::setMode.
- virtual status_t setMode(int mode)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
- data.writeInt32(mode);
- remote()->transact(SET_MODE, data, &reply);
- return reply.readInt32();
- }
- oid IPCThreadState::joinThreadPool(bool isMain)
- mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
- status_t result;
- do {
- int32_t cmd;
- result = talkWithDriver();
- if (result >= NO_ERROR) {
- size_t IN = mIn.dataAvail();
- if (IN < sizeof(int32_t)) continue;
- cmd = mIn.readInt32();
- result = executeCommand(cmd);
- }
- // Let this thread exit the thread pool if it is no longer
- // needed and it is not the main process thread.
- if(result == TIMED_OUT && !isMain) {
- break;
- }
- } while (result != -ECONNREFUSED && result != -EBADF);
- mOut.writeInt32(BC_EXIT_LOOPER);
- talkWithDriver(false);
- case BR_TRANSACTION:
- {
- binder_transaction_data tr;
- Parcel reply;
- if (tr.target.ptr) {
- sp<BBinder> b((BBinder*)tr.cookie);
- const status_t error = b->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
- } else {
- const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
- }
- if ((tr.flags & TF_ONE_WAY) == 0) {
- LOG_ONEWAY("Sending reply to %d!", mCallingPid);
- sendReply(reply, 0);
- } else {
- LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
- }
- }
- break;
- status_t BnAudioFlinger::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- case SET_MODE: {
- CHECK_INTERFACE(IAudioFlinger, data, reply);
- int mode = data.readInt32();
- reply->writeInt32( setMode(mode) );
- return NO_ERROR;
- } break;
- }
- status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
- {
- status_t err;
- status_t statusBuffer;
- err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
- if (err < NO_ERROR) return err;
- return waitForResponse(NULL, NULL);
- }