編輯:關於Android編程
本文參考《Android系統源代碼情景分析》,作者羅升陽
一、測試代碼:
~/Android/external/binder/server
----FregServer.cpp
~/Android/external/binder/common
----IFregService.cpp
----IFregService.h
~/Android/external/binder/client
----FregClient.cpp
Binder庫(libbinder)代碼:
~/Android/frameworks/base/libs/binder
----BpBinder.cpp
----Parcel.cpp
----ProcessState.cpp
----Binder.cpp
----IInterface.cpp
----IPCThreadState.cpp
----IServiceManager.cpp
----Static.cpp
~/Android/frameworks/base/include/binder
----Binder.h
----BpBinder.h
----IInterface.h
----IPCThreadState.h
----IServiceManager.h
----IBinder.h
----Parcel.h
----ProcessState.h
驅動層代碼:
~/Android//kernel/goldfish/drivers/staging/android
----binder.c
----binder.h
二、源碼分析
在Android Binder進程間通信---注冊Service組件---Client發送BC_TRANSACTIONhttp://blog.csdn.net/jltxgcy/article/details/26076149一文中,在最後線程睡眠以等待進程間通信結果。
在http://blog.csdn.net/jltxgcy/article/details/26076149文章中,我們假設請求注冊Service組件FregService的線程thread正在Binder驅動程序函數binder_thread_read中等待Service Manager完成注冊操作。現在既然Service Manager已經完成了對Service組件FregService的注冊,並且線程thread已經被Binder驅動程序喚醒,接下來它就會執行函數binder_thread_read來處理它的todo隊列中的工作項了。
現在請求注冊Service組件FregService的線程thread的todo隊列中有一個類型為BINDER_WORK_TRANSACTION的工作項,因此,接下來我們就分析函數binder_thread_read處理這個工作項的過程。
~/Android//kernel/goldfish/drivers/staging/android
----binder.c
static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, void __user *buffer, int size, signed long *consumed, int non_block) { void __user *ptr = buffer + *consumed; void __user *end = buffer + size; ......... while (1) { uint32_t cmd; struct binder_transaction_data tr; struct binder_work *w; struct binder_transaction *t = NULL; if (!list_empty(&thread->todo)) w = list_first_entry(&thread->todo, struct binder_work, entry);//從線程thread的todo隊列中取出這個類型為BINDER_WORK_TRANSACTION的工作項 else if (!list_empty(&proc->todo) && wait_for_proc_work) w = list_first_entry(&proc->todo, struct binder_work, entry); else { .......... } ..... switch (w->type) { case BINDER_WORK_TRANSACTION: { t = container_of(w, struct binder_transaction, work);//接著又將該工作項的宿主binder_transaction結構體取回來,並且保存在變量t中 } break; ........ if (t->buffer->target_node) {//NULL ....... } else { tr.target.ptr = NULL; tr.cookie = NULL; cmd = BR_REPLY; } tr.code = t->code;//0 tr.flags = t->flags;//0 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;//內核緩沖區的內核空間地址和用戶空間地址相差一個固定值,並且保存在它的成員變量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)))//將binder_transaction_data結構體tr返回 return -EFAULT; ptr += sizeof(tr); ...... list_del(&t->work.entry);//刪除該任務項 t->buffer->allow_user_free = 1;//允許釋放 if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { ........ } else { t->buffer->transaction = NULL; kfree(t);//釋放binder_transaction結構體t ......... } break; } done: *consumed = ptr - buffer;//cmd和binder_transaction_data結構體tr大小之和 ....... return 0; }首先從線程thread的todo隊列中取出這個類型為BINDER_WORK_TRANSACTION的工作項,並且保存在變量w中。接著又將該工作項的宿主binder_transaction結構體取回來,並且保存在變量t中。
然後利用binder_transaction結構體t初始化binder_transaction_data結果體tr。然後將cmdBR_REPLY和tr返回用戶空間。
線程thread執行完成函數binder_thread_read之後,先返回到函數binder_ioctl中,接著再返回IPCThreadState類的成員函數talkWithDriver中,最後返回到IPCThreadState類的成員函數waitForResponse中來處理BR_REPLY返回協議,如下所示:
~/Android/frameworks/base/libs/binder
----IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) { int32_t cmd; int32_t err; while (1) { if ((err=talkWithDriver()) < NO_ERROR) break; ....... cmd = mIn.readInt32();//cmd為BR_REPLY ...... switch (cmd) { ....... case BR_REPLY: { binder_transaction_data tr; err = mIn.read(&tr, sizeof(tr));//從協議緩沖區mIn的內容讀到一個binder_transaction_data結構體tr中 ......... if (reply) {//不為NULL if ((tr.flags & TF_STATUS_CODE) == 0) {//tr.flags為0 reply->ipcSetDataReference(//將保存在binder_transaction結構體tr中的進程間通信結果保存在Parcel對象reply中 reinterpret_cast首先從返回協議緩沖區mIn中讀取一個BR_REPLY返回協議代碼。然後又從協議緩沖區mIn的內容讀到一個binder_transaction_data結構體tr中。(tr.data.ptr.buffer), tr.data_size, reinterpret_cast (tr.data.ptr.offsets), tr.offsets_size/sizeof(size_t), freeBuffer, this); } else { ....... } } else { ........ } } goto finish; ......... } } finish: ..... return err; }
~/Android/frameworks/base/libs/binder
----Parcel.cpp
void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie) { freeDataNoInit(); mError = NO_ERROR; mData = const_cast參數data指向了用來保存進程間通信結果數據的緩沖區,它的大小由參數dataSize來描述。參數object指向了一個Binder對象偏移數組,用來描述保存在進程間通信數據緩沖區的Binder對象的位置,它的大小由參數objectsCount來描述,參數relFunc是一個函數指針,它指向了IPCTheadState類的成員函數freeBuffer,參數relCookie指向了當前線程的IPCThreadState對象。(data);//進程間通信結果數據的緩沖區 mDataSize = mDataCapacity = dataSize;進程間通信結果數據的緩沖區大小 .......... mDataPos = 0; .......... mObjects = const_cast (objects);//偏移數組起始位置 mObjectsSize = mObjectsCapacity = objectsCount;//偏移數組大小 ......... mOwner = relFunc;//freeBuffer mOwnerCookie = relCookie;//當前線程IPCThreadState對象 ........ }
然後依次賦值給Parcel類的不同成員變量,mData是數據緩沖區的其實地址,mDataSize為數據緩沖區大小,mDataPos為下一個用來讀入的位置。mObjects為偏移數組起始地址,mObjetctSize是偏移數組mObjects下一個用於讀入數據的位置,mObjectsCapacity為偏移數組的大小。
mOwner保存著freeBuffer的函數指針,mOwnerCookie保存者當前線程IPCThreadState對象。線程獲得了保存在當前Parcel對象中的進程間通信結果數據之後,它就會析構該Parcel對象,而該Parcel對象在析構時,會調用它的成員變量mOwner和mOwnerCookie來調用IPCTheadState類的成員函數freeBuffer釋放它內部使用的數據緩沖區mData。由於這個數據緩沖區是在Binder驅動程序中分配的,即它指向一個內核緩沖區,因此IPCThreadState類的成員函數freeBuffer會通過BC_FREE_BUFFER命令協議通知Binder驅動程序將內核緩沖區釋放掉。
上一篇文章介紹了MediaPlayer相關內容,這次用兩篇文章來介紹SurfaceView的用法。網上介紹SurfaceView的用法有很多,寫法也層出不同,例如繼承Su
效果圖知識點分析效果圖來看不復雜內容並沒多少,值得介紹一下的知識點也就下面幾個吧- 列表標題懸停- 左右列表滑動時聯動- 添加商品時的拋物線動畫- 底部彈出購物車清單-
算來學習Android開發已有2年的歷史了,在這2年的學習當中,基本掌握了Android的基礎知識。越到後面的學習越感覺困難,一來是自認為android沒啥可學的了(自認
本文實例講述了Android中Matrix用法。分享給大家供大家參考,具體如下:Matrix ,中文裡叫矩陣,高等數學裡有介紹,在圖像處理方面,主要是用於平面的縮放、平移