binderまとめ
データ構造:
上の図では、SMGrにはそれぞれのServiceのbinder引用と自分のbinderエンティティがあり、各ServiceはSMGrのbinder引用と自分のbinderエンティティを持っていますが、clientはSMGrとServiceの参照を持っています.
具体的なプロセス:
1、 まずSMGrは自分のビッドエンティティを作って、デーモンプロセスになります.そして、スレッド構造のthread->todoの上にイベントが来るのを待ちます.
2、 ServiceはまずSMGrの参照を取得し、この引用によってそのadd Service方法を呼び出します.このとき、プロセスのカーネル空間でbinderエンティティを作成し、その参照をSMGrに登録します.
3、 ClientはまずSMGrの引用を取得し、そしてget Serviceを呼び出してSMGrからこのServiceの引用を取得し、そのカーネル空間でこのServiceの引用を作成しました.この方法を呼び出すと、このServiceと直接通信できます.ここでは、clientのServiceへの参照とSMGrでのServiceの参照は違いに注意してください.指し示すbindエンティティは同一です.
この中のデータ転送はメモリを共有することによって行われ、AがBと通信する必要がある場合、Aはカーネル状態に入り、イベントtを作成し、この事物tがどの目標処理に任せるべきかを確認します.目標に空間を割り当てて、データを拷問し、Bがデータを得た後、対応するユーザ空間アドレスにマッピングします.このようにBプロセスのユーザ空間でAからのデータにアクセスすることができます.
(ここの各プロセスのカーネル空間はmmapで作成されます.)
clientがServiceの参照を取得するとServiceのメソッドを呼び出すことができます.カーネル空間で事物tを作成し、ターゲットをこのServiceに設定し、次のような設定コードがあります.
ptr
和
クッキー
はい、あります
サービス
登録する時初期化しました.登録してください.
サービス
の時、
サービス
呼び出しました
flatenbinder
一つ伝わってきた
IBinder
この対角はこれです.
サービス
3、データ転送プロセス:
まずIPCThreadState:writeTransation Data関数では、下記のコードでデータをmOutに保存します.ここの構造はbinder_であることに注意してください.トランスアクションダタ
カーネルの中ではBINDER(u)に対してWRITE_READは、write_によりsizeが0より大きいので、ret=binder_を呼び出します.スリーロード.write(proc,thread,(void_user*)bwr.writemuffer,bwr.writemusize,&bwr.writemend)処理は、この関数の中でBC(u)に対して処理されます.TRANSACTIONの処理は
4、ビッドリレー
まずaddServiceで
ここにはobjのオフセットが保存されています.
続いて、writeTransation Dataを呼び出して、データをmOutに書きます.
tr.data_sizeは書き込みのデータサイズです.
tr.data.ptr.bufferが書き込んでいるのはデータの開始ポインタです.
tr.offsets_size書き込みはビッドの合計サイズ、個数*単一サイズです.
tr.data.ptr.offsetsに書き込まれたbinderの開始アドレス
データがカーネルに届いたら、ビダにいます.トランスアクションはこのビッド本体を処理しました.
このようにtargetプロセスが呼び覚まされたら処理に入ります.ここでadd serviceは普通service_です.manage
次の流れに入ります.
以下はクライアントがservicesを取得するのを待つことができます.
クライアントはまずservicesを取得して、getServiceを呼び出して、中はcheck Serviceを呼び出して、servcieの名前を書いて、binderを通じて駆動して、パラメータをservice managerの過程に書いて、それを呼び覚ましてから、ユーザー空間でdouを呼び出します.find_serviceが見つかる前に私たちが追加したservicesは、このserviceのmanagerの中のハンドルの値をドライバに書き込みます.transaction関数では、このserviceの引用を新たにNewします.この引用は、serviceを要求するclient端の引用であり、managerの引用とは異なります.そしてこの引用をclientに返します.
clientのユーザ空間で、reply.readStrongBinder関数の実現によって、binderを取得する.
5、関連構造図:
残りの何時:
1、binder_ブザーの割り当て
2、いつ事務を全体のプロジェクトの列に置きますか?いつthreadの列に入れますか?
3、死亡のお知らせ
参考:
http://blog.csdn.net/lizhiguo0532?view mode=contensts
//open , /dev/binder , struct file private_data
struct binder_proc {
struct hlist_node proc_node;
struct rb_root threads;// binder_proc , max_threads
struct rb_root nodes;// binder_proc Binder
struct rb_root refs_by_desc;// key binder_proc Binder , Binder
struct rb_root refs_by_node;// key binder_proc Binder , Binder
int pid;
struct vm_area_struct *vma;
struct task_struct *tsk;
struct files_struct *files;
struct hlist_node deferred_work_node;
int deferred_work;
void *buffer;//
ptrdiff_t user_buffer_offset;//
struct list_head buffers;
struct rb_root free_buffers;
struct rb_root allocated_buffers;
size_t free_async_space;
struct page **pages;//
size_t buffer_size;//
uint32_t buffer_free;
struct list_head todo;
wait_queue_head_t wait;//
struct binder_stats stats;
struct list_head delivered_death;
int max_threads;//
int requested_threads;
int requested_threads_started;
int ready_threads;
long default_priority;//
struct dentry *debugfs_entry;
};
// binder_proc buffer ~ (buffer + buffer_size) , , struct binder_buffer
struct binder_buffer {
struct list_head entry; // struct binder_proc buffers
struct rb_node rb_node; // struct binder_proc free_buffers
// struct binder_proc allocated_buffers
unsigned free:1;//
unsigned allow_user_free:1;
unsigned async_transaction:1;
unsigned debug_id:29;
struct binder_transaction *transaction;
struct binder_node *target_node;//
size_t data_size;//
size_t offsets_size;//
uint8_t data[0];//
};
//
struct binder_thread {
struct binder_proc *proc;//
struct rb_node rb_node;// binder_proc threads
int pid;
int looper;//
struct binder_transaction *transaction_stack;//
struct list_head todo;//
uint32_t return_error; //
uint32_t return_error2; //
wait_queue_head_t wait;
struct binder_stats stats;
};
// binder
struct binder_node {
int debug_id;
struct binder_work work;
union {
struct rb_node rb_node;// Binder , rb_node proc->nodes
struct hlist_node dead_node;// Binder , Binder , Binder dead_node
};
struct binder_proc *proc;//
struct hlist_head refs;// Binder Binder
int internal_strong_refs;//
int local_weak_refs;//
int local_strong_refs;//
void __user *ptr;//
void __user *cookie;//
unsigned has_strong_ref:1;
unsigned pending_strong_ref:1;
unsigned has_weak_ref:1;
unsigned pending_weak_ref:1;
unsigned has_async_transaction:1;
unsigned accept_fds:1;
unsigned min_priority:8;
struct list_head async_todo;
};
// ioctl bind
struct binder_write_read {
signed long write_size; //
signed long write_consumed; //
unsigned long write_buffer; // struct binder_transaction_data
signed long read_size; //
signed long read_consumed; //
unsigned long read_buffer; // struct binder_transaction_data
};
struct binder_transaction_data {
/* The first two are only used for bcTRANSACTION and brTRANSACTION,
* identifying the target and contents of the transaction.
*/
union {
size_t handle; //
void *ptr; // Binder , ptr
} target;
void *cookie; //
unsigned int code; //
/* General information about the transaction. */
unsigned int flags;
pid_t sender_pid;// pid
uid_t sender_euid;// ID
size_t data_size; //data.buffer
size_t offsets_size;//data.offsets , data.buffer , Binder
/* If this transaction is inline, the data immediately
* follows here; otherwise, it ends with a pointer to
* the data buffer.
*/
union {
struct {
/* transaction data */
const void *buffer;// , :
// 1、
//2、Binder Binder
/* offsets from buffer to flat_binder_object structs */
const void *offsets;
} ptr;
uint8_t buf[8];
} data;
};
// Binder
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
unsigned long type;//Binder
unsigned long flags;//Binder
/* 8 bytes of data. */
union {
void *binder; // Binder
signed long handle; // Binder
};
void *cookie;//
};
// ,
struct binder_transaction {
int debug_id;//
struct binder_work work;
struct binder_thread *from;//
struct binder_transaction *from_parent;
struct binder_proc *to_proc;//
struct binder_thread *to_thread;//
struct binder_transaction *to_parent;
unsigned need_reply:1;
/* unsigned is_dead:1; */ /* not used at the moment */
struct binder_buffer *buffer;// ,
unsigned int code;//
unsigned int flags;
long priority;
long saved_priority;
uid_t sender_euid;// euid
};
struct binder_work {
struct list_head entry;// , binder_work
enum {
BINDER_WORK_TRANSACTION = 1,
BINDER_WORK_TRANSACTION_COMPLETE,
BINDER_WORK_NODE,
BINDER_WORK_DEAD_BINDER,
BINDER_WORK_DEAD_BINDER_AND_CLEAR,
BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
} type;
};
enum transaction_flags {
TF_ONE_WAY = 0x01, // , ,
TF_ROOT_OBJECT = 0x04, // , Binder
TF_STATUS_CODE = 0x08, // 32 , “ ”( handle)
TF_ACCEPT_FDS = 0x10, // , (BINDER_TYPE_FD), handle
};
//binder
struct binder_ref {
/* Lookups needed: */
/* node + proc => ref (transaction) */
/* desc + proc => ref (transaction, inc/dec ref) */
/* node => refs + procs (proc exit) */
int debug_id;
struct rb_node rb_node_desc;// binder_ref
struct rb_node rb_node_node;// binder binder_ref
struct hlist_node node_entry;
struct binder_proc *proc;
struct binder_node *node; // binder
uint32_t desc;
int strong;
int weak;
struct binder_ref_death *death;
};
2、上の図では、SMGrにはそれぞれのServiceのbinder引用と自分のbinderエンティティがあり、各ServiceはSMGrのbinder引用と自分のbinderエンティティを持っていますが、clientはSMGrとServiceの参照を持っています.
具体的なプロセス:
1、 まずSMGrは自分のビッドエンティティを作って、デーモンプロセスになります.そして、スレッド構造のthread->todoの上にイベントが来るのを待ちます.
2、 ServiceはまずSMGrの参照を取得し、この引用によってそのadd Service方法を呼び出します.このとき、プロセスのカーネル空間でbinderエンティティを作成し、その参照をSMGrに登録します.
3、 ClientはまずSMGrの引用を取得し、そしてget Serviceを呼び出してSMGrからこのServiceの引用を取得し、そのカーネル空間でこのServiceの引用を作成しました.この方法を呼び出すと、このServiceと直接通信できます.ここでは、clientのServiceへの参照とSMGrでのServiceの参照は違いに注意してください.指し示すbindエンティティは同一です.
この中のデータ転送はメモリを共有することによって行われ、AがBと通信する必要がある場合、Aはカーネル状態に入り、イベントtを作成し、この事物tがどの目標処理に任せるべきかを確認します.目標に空間を割り当てて、データを拷問し、Bがデータを得た後、対応するユーザ空間アドレスにマッピングします.このようにBプロセスのユーザ空間でAからのデータにアクセスすることができます.
(ここの各プロセスのカーネル空間はmmapで作成されます.)
clientがServiceの参照を取得するとServiceのメソッドを呼び出すことができます.カーネル空間で事物tを作成し、ターゲットをこのServiceに設定し、次のような設定コードがあります.
tr.target.ptr = target_node->ptr;
tr.cookie = target_node->cookie;
ここのptr
和
クッキー
はい、あります
サービス
登録する時初期化しました.登録してください.
サービス
の時、
サービス
呼び出しました
flatenbinder
一つ伝わってきた
IBinder
この対角はこれです.
サービス
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;
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = NULL;
obj.cookie = NULL;
}
return finish_flatten_binder(binder, obj, out);
}
このように、Serviceがカーネル空間でイベントを取得してユーザ空間に戻ると、以下のコマンドによってbinderユーザエンティティに変換される.if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
if (error < NO_ERROR) reply.setError(error);
}
書き換えたトランジットを呼び出して対応する機能を実現します.3、データ転送プロセス:
まずIPCThreadState:writeTransation Data関数では、下記のコードでデータをmOutに保存します.ここの構造はbinder_であることに注意してください.トランスアクションダタ
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;
}
そしてIPCThreadState:talkWithDriverでstatus_t IPCThreadState::talkWithDriver(bool doReceive)
{
LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
binder_write_read bwr;
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (long unsigned int)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (long unsigned int)mIn.data();
} else {
bwr.read_size = 0;
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
if (outAvail != 0) {
alog << "Sending commands to driver: " << indent;
const void* cmds = (const void*)bwr.write_buffer;
const void* end = ((const uint8_t*)cmds)+bwr.write_size;
alog << HexDump(cmds, bwr.write_size) << endl;
while (cmds < end) cmds = printCommand(alog, cmds);
alog << dedent;
}
alog << "Size of receive buffer: " << bwr.read_size
<< ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
}
// Return immediately if there is nothing to do.
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
IF_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
#if defined(HAVE_ANDROID_OS)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);
......
}
先にmOutに保存したデータを取得してbinder_に保存します.write_read構造の中のwrite_ブザーは、Octl(mProcess->mDriverFDを呼び出し、BINDERWRITEuREAD、&bwr)データをカーネルに転送します.カーネルの中ではBINDER(u)に対してWRITE_READは、write_によりsizeが0より大きいので、ret=binder_を呼び出します.スリーロード.write(proc,thread,(void_user*)bwr.writemuffer,bwr.writemusize,&bwr.writemend)処理は、この関数の中でBC(u)に対して処理されます.TRANSACTIONの処理は
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;
}
binderにいますtransactionでは、ターゲットプロセスのカーネル空間に該当するデータをコピーします. t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
if (t->buffer == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_alloc_buf_failed;
}
t->buffer->allow_user_free = 0;
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
if (target_node)
binder_inc_node(target_node, 1, 0, NULL);
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
binder_user_error("binder: %d:%d got transaction with invalid "
"data ptr
", proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
binder_user_error("binder: %d:%d got transaction with invalid "
"offsets ptr
", proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
このようにデータは目的のプロセスになります.目標のプロセスは一般的にbinder_で寝ます.スリーロード.read関数のwait_イベントinterruptibleexclusiveでは、起動後に前の要求プロセスのトランザクションtのデータをローカル変数struct binderにコピーします.トランスアクションdata trでは、データを対応するユーザ空間アドレスにマッピングする. tr.code = t->code;
tr.flags = t->flags;
tr.sender_euid = t->sender_euid;
if (t->from) {
struct task_struct *sender = t->from->proc->tsk;
tr.sender_pid = task_tgid_nr_ns(sender,
current->nsproxy->pid_ns);
} else {
tr.sender_pid = 0;
}
tr.data_size = t->buffer->data_size;
tr.offsets_size = t->buffer->offsets_size;
tr.data.ptr.buffer = (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);
put_を呼び出しますuserはtrの内容をユーザーから転送されたバッファにコピーし、ポインタptrはこのユーザーバッファのアドレスを指し、その後ターゲットプロセスの処理関数に戻ってデータを処理します.このように主に完成したデータは一つのプロセスから別のプロセスに伝えられます.データのコピーも一つしかありません.つまり、ユーザ空間からカーネル空間までです.4、ビッドリレー
まずaddServiceで
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.readExceptionCode() : err;
}
ここでビットを書き込みます.data.writeStrongBinder(service);
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
struct flat_binder_objectは転送中の1つのbinderオブジェクトを表し、その定義は以下の通りである./*
* This is the flattened representation of a Binder object for transfer
* between processes. The 'offsets' supplied as part of a binder transaction
* contains offsets into the data where these structures occur. The Binder
* driver takes care of re-writing the structure type and data as it moves
* between processes.
*/
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
unsigned long type;
unsigned long flags;
/* 8 bytes of data. */
union {
void *binder; /* local object */
signed long handle; /* remote object */
};
/* extra data associated with local object */
void *cookie;
};
flatenを見てくださいbinderstatus_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;
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = NULL;
obj.cookie = NULL;
}
return finish_flatten_binder(binder, obj, out);
}
伝わってくるビッドは普通BBinderからのローカルBinderエンティティを継承しているので、binder->local BinderはBBinderポインタを返します.そして、必ず空ではないです.obj.type = BINDER_TYPE_BINDER;
obj.binder = local->getWeakRefs();
obj.cookie = local;
関数の最後の呼び出しfinish_flatenbinderがこれをflat_に来ます.binder_ObjはParcelに書き込みます.status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
{
const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
const bool enoughObjects = mObjectsSize < mObjectsCapacity;
if (enoughData && enoughObjects) {
restart_write:
*reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
// Need to write meta-data?
if (nullMetaData || val.binder != NULL) {
mObjects[mObjectsSize] = mDataPos;
acquire_object(ProcessState::self(), val, this);
mObjectsSize++;
}
// remember if it's a file descriptor
if (val.type == BINDER_TYPE_FD) {
mHasFds = mFdsKnown = true;
}
return finishWrite(sizeof(flat_binder_object));
}
if (!enoughData) {
const status_t err = growData(sizeof(val));
if (err != NO_ERROR) return err;
}
if (!enoughObjects) {
size_t newSize = ((mObjectsSize+2)*3)/2;
size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
if (objects == NULL) return NO_MEMORY;
mObjects = objects;
mObjectsCapacity = newSize;
}
goto restart_write;
}
*reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;
ここで関連データを書き込みます.ここにはobjのオフセットが保存されています.
mObjects[mObjectsSize] = mDataPos;
ここでは、プロセス間で伝送されるデータ間にBinderオブジェクトがある場合、Binderドライバは、各Binderエンティティの整合性を維持するために、さらなる処理を行う必要があるからです.続いて、writeTransation Dataを呼び出して、データをmOutに書きます.
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;
}
ここで呼び出したのは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();
ここですtr.data_sizeは書き込みのデータサイズです.
tr.data.ptr.bufferが書き込んでいるのはデータの開始ポインタです.
tr.offsets_size書き込みはビッドの合計サイズ、個数*単一サイズです.
tr.data.ptr.offsetsに書き込まれたbinderの開始アドレス
データがカーネルに届いたら、ビダにいます.トランスアクションはこのビッド本体を処理しました.
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, fp->cookie);
if (node == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_new_node_failed;
}
node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
}
if (fp->cookie != node->cookie) {
......
goto err_binder_get_ref_for_node_failed;
}
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);
......
} break;
ここのタイプはBINDER_です.TYPE_BINDERは、一般的にadd servicesの時に、Binderドライバプログラムでこのservicesを転送するのは初めてで、先にbinderエンティティを取得して、binderを呼び出します.ゲットするnode関数がこのBinderエンティティを調べたら、空に戻ります.new_nodeはprocの中で新しいbinderを作ります.nodeエンティティこのbinderエンティティを他のタリガーに預けて管理するため、ここで引用を作成します.次の二つの点に注意してください. if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->handle = ref->desc;
typeをHANDLEに設定します.このbinderはtargetで処理しますので、targetではハンドル値のみでBinderエンティティを引用することができます.だから後はfp->handleを参照値に設定します.このようにtargetプロセスが呼び覚まされたら処理に入ります.ここでadd serviceは普通service_です.manage
次の流れに入ります.
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;
uint32_t strict_policy;
if (txn->target != svcmgr_handle)
return -1;
// Equivalent to Parcel::enforceInterface(), reading the RPC
// header with the strict mode policy mask and the interface name.
// Note that we ignore the strict_policy and don't propagate it
// further (since we do no outbound RPCs anyway).
strict_policy = bio_get_uint32(msg);
s = bio_get_string16(msg, &len);
if ((len != (sizeof(svcmgr_id) / 2)) ||
memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
fprintf(stderr,"invalid id %s
", 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;
......
}
bio_put_uint32(reply, 0);
return 0;
}
ここですstrict_policy = bio_get_uint32(msg);
s = bio_get_string16(msg, &len);
s = bio_get_string16(msg, &len);
ptr = bio_get_ref(msg);
前に書いた値を順に読みなさい.ビオ_ゲットするobjという関数はbinder_からです.ioで一番最初に取得したのはまだ取っていないビッドカーです.object、続いてdouを呼び出します.add_serviceはserviceのnameとハンドルの値を保存します.以下はクライアントがservicesを取得するのを待つことができます.
クライアントはまずservicesを取得して、getServiceを呼び出して、中はcheck Serviceを呼び出して、servcieの名前を書いて、binderを通じて駆動して、パラメータをservice managerの過程に書いて、それを呼び覚ましてから、ユーザー空間でdouを呼び出します.find_serviceが見つかる前に私たちが追加したservicesは、このserviceのmanagerの中のハンドルの値をドライバに書き込みます.transaction関数では、このserviceの引用を新たにNewします.この引用は、serviceを要求するclient端の引用であり、managerの引用とは異なります.そしてこの引用をclientに返します.
clientのユーザ空間で、reply.readStrongBinder関数の実現によって、binderを取得する.
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
ここでunflatenを呼び出しました.Binder関数は、Binderオブジェクトを構築するために使用されます.status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = static_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
ここのflat->typeはBINDER_です.TYPE_HANDLEは、それでProcesStateを呼び出す:get StrongProxyForHandle関数: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;
}
ここでは、ProcessStateは使ったBinderリモートインターフェースをキャッシュしています.このようにして、次回Service Managerから同じハンドルを要求したら、直接にこのBinderリモートインターフェースに戻ります.もう一つ作成しなくてもいいです.ここは初めて使うので、e-binderは空です.そこでBpBinderオブジェクトを作成しました.b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
このようにして、binderを獲得しました.これからはこのbinderを通じてserviceと通信できます.5、関連構造図:
残りの何時:
1、binder_ブザーの割り当て
2、いつ事務を全体のプロジェクトの列に置きますか?いつthreadの列に入れますか?
3、死亡のお知らせ
参考:
http://blog.csdn.net/lizhiguo0532?view mode=contensts