Android跨進程通信IPC整體內容如下
- 1、Android跨進程通信IPC之1——Linux基礎
- 2、Android跨進程通信IPC之2——Bionic
- 3、Android跨進程通信IPC之3——關于"JNI"的那些事
- 4、Android跨進程通信IPC之4——AndroidIPC基礎1
- 4、Android跨進程通信IPC之4——AndroidIPC基礎2
- 5、Android跨進程通信IPC之5——Binder的三大接口
- 6、Android跨進程通信IPC之6——Binder框架
- 7、Android跨進程通信IPC之7——Binder相關結構體簡介
- 8、Android跨進程通信IPC之8——Binder驅動
- 9、Android跨進程通信IPC之9——Binder之Framework層C++篇1
- 9、Android跨進程通信IPC之9——Binder之Framework層C++篇2
- 10、Android跨進程通信IPC之10——Binder之Framework層Java篇
- 11、Android跨進程通信IPC之11——AIDL
- 12、Android跨進程通信IPC之12——Binder補充
- 13、Android跨進程通信IPC之13——Binder總結
- 14、Android跨進程通信IPC之14——其他IPC方式
- 15、Android跨進程通信IPC之15——感謝
本篇文章的主要內容
- Binder中的線程池
- Binder的權限
- Binder的死亡通知機制
一 、Binder中的線程池
客戶端在使用Binder可以調用服務端的方法,這里面有一些隱含的問題,如果我們服務端的方法是一個耗時的操作,那么對于我們客戶端和服務端都存在風險,如果有很多客戶端都來調用它的方法,那么是否會造成ANR那?多個客戶端調用,是否會有同步問題?如果客戶端在UI線程中調用的這個是耗時方法,那么是不是它也會造成ANR?這些問題都是真實存在的,首先第一個問題是不會出現,因為服務端所有這些被調用方法都是在一個線程池中執行的,不在服務端的UI線程中,因此服務端不會ANR,但是服務端會有同步問題,因此我們提供的服務端接口方法應該注意同步問題。客戶端會ANR很容易解決,就是我們不要在UI線程中就可以避免了。那我們一起來看下Binder的線程池
(一) Binder線程池簡述
Android系統啟動完成后,ActivityManager、PackageManager等各大服務都運行在system_server進程,app應用需要使用系統服務都是通過Binder來完成進程間的通信,那么對于Binder線程是如何管理的?又是如何創建的?其實無論是system_server進程還是app進程,都是在fork完成后,便會在新進程中執行onZygoteInit()的過程,啟動Binder線程池。
從整體架構以及通信協議的角度來闡述了Binder架構。那對于binder線程是如何管理的呢,又是如何創建的呢?其實無論是system_server進程,還是app進程,都是在進程fork完成后,便會在新進程中執行onZygoteInit()的過程中,啟動binder線程池。
(二) Binder線程池創建
Binder 線程創建與其坐在進程的創建中產生,Java層進程的創建都是通過Process.start()方法,向Zygote進程發出創建進程的socket消息,Zygote收到消息后會調用Zygote.forkAndSpecialize()來fork出新進程,在新進程中調用RuntimeInit.nativeZygoteInit()方法,該方法經過JNI映射,最終會調用app_main.cpp中的onZygoteInit,那么接下來從這個方法開始。
1、onZygoteInit()
代碼在app_main.cpp 的91行
virtual void onZygoteInit()
{
// 獲取 ProcessState對象
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
ProcessState主要工作是調用open()打開/dev/binder驅動設備,再利用mmap()映射內核的地址空間,將Binder驅動的fd賦值ProcessState對象的變量mDriverFD,用于交互操作。startThreadPool()是創建一個型的Binder線程,不斷進行talkWithDriver()。
2、ProcessState.startThreadPool()
代碼在ProcessState.cpp 的132行
void ProcessState::startThreadPool()
{
//多線程同步
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
啟動Binder線程池后,則設置mThreadPoolStarted=true,通過變量mThreadPoolStarted來保證每個應用進程只允許啟動一個Binder線程池,且本次創建的是Binder主線程(isMain=true,isMain具體請看spawnPooledThread(true))。其余Binder線程池中的線程都是由Binder驅動來控制創建的。然后繼續跟蹤看下spawnPooledThread(true)函數
3、ProcessState. spawnPooledThread()
代碼在ProcessState.cpp 的286行
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
//獲取Binder線程名
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
//這里注意isMain=true
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());
}
}
3.1、ProcessState. makeBinderThreadName()
代碼在ProcessState.cpp 的279行
String8 ProcessState::makeBinderThreadName() {
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
String8 name;
name.appendFormat("Binder_%X", s);
return name;
}
獲取Binder的線程名,格式為Binder_X,其中X為整數,每個進程中的Binder編碼是從1開始,依次遞增;只有通過makeBinderThreadName()方法來創建線程才符合這個格式,對于直接將當前線程通過joinThreadPool()加入線程池的線程名則不符合這個命名規則。另外,目前Android N中Binder命令已改為Binder:<pid> _X,則對于分析問題很有幫助,通過Binder名稱的pid就可以很快定位到該Binder所屬進程的pid
3.2、PoolThread.run
代碼在ProcessState.cpp 的52行
class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
從函數名看起來是創建線程池,其實就只是創建一個線程,該PoolThread繼承Thread類,t->run()函數最終會調用PoolThread的threadLooper()方法。
4、IPCThreadState. joinThreadPool()
代碼在IPCThreadState.cpp.cpp 的52行
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
// 創建Binder線程
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
// This thread may have been spawned by a thread that was in the background
// scheduling group, so first we will make sure it is in the foreground
// one to avoid performing an initial transaction in the background.
//設置前臺調度策略
set_sched_policy(mMyThreadId, SP_FOREGROUND);
status_t result;
do {
//清楚隊列的引用
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
// 處理下一條指令
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
abort();
}
// 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) {
//非主線程出現timeout則線程退出
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
(void*)pthread_self(), getpid(), (void*)result);
// 線程退出循環
mOut.writeInt32(BC_EXIT_LOOPER);
//false代表bwr數據的read_buffer為空
talkWithDriver(false);
}
- 1 對于isMain=true的情況下,command為BC_ENTER_LOOPER,代表的是Binder主線程,不會退出線程。
- 2 對于isMain=false的情況下,command為BC_REGISTER_LOOPER,表示的是binder驅動創建的線程。
joinThreadLoop()里面有一個do——while循環,這個thread里面主要的調用,也就是重點,里面主要就是調用了兩個函數processPendingDerefs()和getAndExecuteCommand()函數,那我們依次來看下。
4.1、IPCThreadState. processPendingDerefs()
代碼在IPCThreadState.cpp 的454行
// When we've cleared the incoming command queue, process any pending derefs
void IPCThreadState::processPendingDerefs()
{
if (mIn.dataPosition() >= mIn.dataSize()) {
size_t numPending = mPendingWeakDerefs.size();
if (numPending > 0) {
for (size_t i = 0; i < numPending; i++) {
RefBase::weakref_type* refs = mPendingWeakDerefs[i];
//弱引用減一
refs->decWeak(mProcess.get());
}
mPendingWeakDerefs.clear();
}
numPending = mPendingStrongDerefs.size();
if (numPending > 0) {
for (size_t i = 0; i < numPending; i++) {
BBinder* obj = mPendingStrongDerefs[i];
//強引用減一
obj->decStrong(mProcess.get());
}
mPendingStrongDerefs.clear();
}
}
}
我們知道了processPendingDerefs()這個函數主要是將mPendingWeakDerefs和mPendingStrongDerefs中的指針解除應用,而且他的執行結果并不影響Loop的執行,那我們主要看下getAndExecuteCommand()函數里面做了什么。
4.2、IPCThreadState. getAndExecuteCommand()
代碼在IPCThreadState.cpp 的414行
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
//與binder進行交互
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing top-level Command: "
<< getReturnString(cmd) << endl;
}
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;
pthread_mutex_unlock(&mProcess->mThreadCountLock);
// 執行Binder響應嗎
result = executeCommand(cmd);
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount--;
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
pthread_mutex_unlock(&mProcess->mThreadCountLock);
// After executing the command, ensure that the thread is returned to the
// foreground cgroup before rejoining the pool. The driver takes care of
// restoring the priority, but doesn't do anything with cgroups so we
// need to take care of that here in userspace. Note that we do make
// sure to go in the foreground after executing a transaction, but
// there are other callbacks into user code that could have changed
// our group so we want to make absolutely sure it is put back.
set_sched_policy(mMyThreadId, SP_FOREGROUND);
}
return result;
}
我們知道了getAndExecuteCommand()主要就是調用兩個函數talkWithDriver()和executeCommand(),我們分別看一下
4.2.1、ProcessState. talkWithDriver()
代碼在IPCThreadState.cpp 的803行
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
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 = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 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)
// ioctl執行binder讀寫操作,經過syscall,進入Binder驅動,調用Binder_ioctl
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);
IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << endl;
}
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
alog << "Remaining data size: " << mOut.dataSize() << endl;
alog << "Received commands from driver: " << indent;
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
alog << HexDump(cmds, mIn.dataSize()) << endl;
while (cmds < end) cmds = printReturnCommand(alog, cmds);
alog << dedent;
}
return NO_ERROR;
}
return err;
}
在這里調用的是isMain=true,也就是向mOut寫入的是便是BC_ENTER_LOOPER。后面就是進入Binder驅動了,具體到binder_thread_write()函數的BC_ENTER_LOOPER的處理過程。
4.2.1.1、binder_thread_write
代碼在binder.c 的2252行
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
//拷貝用戶空間的cmd命令,此時為BC_ENTER_LOOPER
if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
ptr += sizeof(uint32_t);
switch (cmd) {
case BC_REGISTER_LOOPER:
if (thread->looper & BINDER_LOOPER_STATE_ENTERED) {
//出錯原因:線程調用完BC_ENTER_LOOPER,不能執行該分支
thread->looper |= BINDER_LOOPER_STATE_INVALID;
} else if (proc->requested_threads == 0) {
//出錯原因:沒有請求就創建線程
thread->looper |= BINDER_LOOPER_STATE_INVALID;
} else {
proc->requested_threads--;
proc->requested_threads_started++;
}
thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
break;
case BC_ENTER_LOOPER:
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
//出錯原因:線程調用完BC_REGISTER_LOOPER,不能立刻執行該分支
thread->looper |= BINDER_LOOPER_STATE_INVALID;
}
//創建Binder主線程
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
case BC_EXIT_LOOPER:
thread->looper |= BINDER_LOOPER_STATE_EXITED;
break;
}
...
}
*consumed = ptr - buffer;
}
return 0;
}
處理完BC_ENTER_LOOPER命令后,一般情況下成功設置thread->looper |= BINDER_LOOPER_STATE_ENTERED。那么binder線程的創建是在什么時候?那就當該線程有事務需要處理的時候,進入binder_thread_read()過程。
4.2.1.2、binder_thread_read
代碼在binder.c 的2654行
binder_thread_read(){
...
retry:
//當前線程todo隊列為空且transaction棧為空,則代表該線程是空閑的
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);
if (thread->return_error != BR_OK && ptr < end) {
...
put_user(thread->return_error, (uint32_t __user *)ptr);
ptr += sizeof(uint32_t);
//發生error,則直接進入done
goto done;
}
thread->looper |= BINDER_LOOPER_STATE_WAITING;
if (wait_for_proc_work)
//可用線程個數+1
proc->ready_threads++;
binder_unlock(__func__);
if (wait_for_proc_work) {
if (non_block) {
...
} else
//當進程todo隊列沒有數據,則進入休眠等待狀態
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} else {
if (non_block) {
...
} else
//當線程todo隊列沒有數據,則進入休眠等待狀態
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}
binder_lock(__func__);
if (wait_for_proc_work)
//可用線程個數-1
proc->ready_threads--;
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
if (ret)
//對于非阻塞的調用,直接返回
return ret;
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
//先考慮從線程todo隊列獲取事務數據
if (!list_empty(&thread->todo)) {
w = list_first_entry(&thread->todo, struct binder_work, entry);
//線程todo隊列沒有數據, 則從進程todo對獲取事務數據
} else if (!list_empty(&proc->todo) && wait_for_proc_work) {
w = list_first_entry(&proc->todo, struct binder_work, entry);
} else {
... //沒有數據,則返回retry
}
switch (w->type) {
case BINDER_WORK_TRANSACTION: ... break;
case BINDER_WORK_TRANSACTION_COMPLETE:... break;
case BINDER_WORK_NODE: ... break;
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION:
struct binder_ref_death *death;
uint32_t cmd;
death = container_of(w, struct binder_ref_death, work);
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
else
cmd = BR_DEAD_BINDER;
put_user(cmd, (uint32_t __user *)ptr;
ptr += sizeof(uint32_t);
put_user(death->cookie, (void * __user *)ptr);
ptr += sizeof(void *);
...
if (cmd == BR_DEAD_BINDER)
goto done; //Binder驅動向client端發送死亡通知,則進入done
break;
}
if (!t)
continue; //只有BINDER_WORK_TRANSACTION命令才能繼續往下執行
...
break;
}
done:
*consumed = ptr - buffer;
//創建線程的條件
if (proc->requested_threads + proc->ready_threads == 0 &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
proc->requested_threads++;
// 生成BR_SPAWN_LOOPER命令,用于創建新的線程
put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer);
}
return 0;
}
放生一下三種情況中的任意一種,就會進入done
- 當前線程return_error發生error的情況
- 當Binder驅動向client端發送死亡通知的情況
- 當類型為BINDER_WORK_TRANSACTION(即受到命令是BC_TRANSACTION或BC_REPLY)的情況
任何一個Binder線程當同事滿足以下條件時,則會生成用于創建新線程的BR_SPAWN_LOOPER命令:
- 1、當前進程中沒有請求創建binder線程,即request_threads=0
- 2、當前進程沒有空閑可用binder線程,即ready_threads=0(線程進入休眠狀態的個數就是空閑線程數)
- 3、當前線程應啟動線程個數小于最大上限(默認是15)
- 4、當前線程已經接收到BC_ENTER_LOOPER或者BC_REGISTER_LOOPEE命令,即當前處于BINDER_LOOPER_STATE_REGISTERED或者BINDER_LOOPER_STATE_ENTERED狀態。
4.2.2、IPCThreadState. executeCommand()
代碼在IPCThreadState.cpp 的947行
status_t IPCThreadState::executeCommand(int32_t cmd)
{
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
...
case BR_SPAWN_LOOPER:
//創建新的binder線程
mProcess->spawnPooledThread(false);
break;
...
}
return result;
}
Binder主線程的創建時在其所在進程創建的過程中一起創建的,后面再創建的普通binder線程是由
spawnPooledThread(false)方法所創建的。
(三) Binder線程池流程
Binder設計架構中,只有第一個Binder主線程也就是Binder_1線程是由應用程序主動創建的,Binder線程池的普通線程都是Binder驅動根據IPC通信需求而創建,Binder線程的創建流程圖如下:
每次由Zygote fork出新進程的過程中,伴隨著創建binder線程池,調用spawnPooledThread來創建binder主線程。當線程執行binder_thread_read的過程中,發現當前沒有空閑線程,沒有請求創建線程,且沒有達到上限,則創建新的binder線程。
Binder的transaction有3種類型:
-call:發起進程的線程不一定是Binder線程,大多數情況下,接受者只指向進程,并不確定會有兩個線程來處理,所以不指定線程。
- reply:發起者一定是binder線程,并且接收者線程便是上此call時的發起線程(該線程不一定是binder線程,可以是任意線程)
- async:與call類型差不多,唯一不同的是async是oneway方式,不需要回復,發起進程的線程不一定是在Binder線程,接收者只指向進程,并不確定會有那個線程來處理,所以不指定線程。
Binder系統中可分為3類binder線程:
- Binder主線程:進程創建過程會調用startThreadPool過程再進入spawnPooledThread(true),來創建Binder主線程。編號從1開始,也就是意味著binder主線程名為binder_1,并且主線程是不會退出的。
- Binder普通線程:是由Binder Driver是根據是否有空閑的binder線程來決定是否創建binder線程,回調spawnPooledThread(false) ,isMain=false,該線程名格式為binder_x
- Binder其他線程:其他線程是指并沒有調用spawnPooledThread方法,而是直接調用IPCThreadState.joinThreadPool(),將當前線程直接加入binder線程隊列。例如:mediaserver和servicemanager的主線程都是binder主線程,但是system_server的主線程并非binder主線程。
二、Binder的權限
(一) 概述
前面關于Binder的文章,講解了Binder的IPC機制。看過Android系統源代碼的讀者一定看到過Binder.clearCallingIdentity(),Binder.restoreCallingIdentity(),定義在Binder.java文件中
// Binder.java
//清空遠程調用端的uid和pid,用當前本地進程的uid和pid替代
public static final native long clearCallingIdentity();
// 作用是回復遠程調用端的uid和pid信息,正好是"clearCallingIdentity"的飯過程
public static final native void restoreCallingIdentity(long token);
這兩個方法都涉及了uid和pid,每個線程都有自己獨一無二IPCThreadState對象,記錄當前線程的pid和uid,可通過方法Binder.getCallingPid()和Binder.getCallingUid()**獲取相應的pic和uid。
clearCallingIdentity(),restoreCallingIdentity()這兩個方法使用過程都是成對使用的,這兩個方法配合使用,用于權限控制檢測功能。
(二) 原理
從定義這兩個方法是native方法,通過Binder的JNI調用,在android_util_Binder.cpp文件中定義了native兩個方法所對應的jni方法。
1、clearCallingIdentity
代碼在android_util_Binder.cpp 771行
static jlong android_os_Binder_clearCallingIdentity(JNIEnv* env, jobject clazz)
{
return IPCThreadState::self()->clearCallingIdentity();
}
這里面代碼混簡單,就是調用了IPCThreadState的clearCallingIdentity()方法
1.1、IPCThreadState::clearCallingIdentity()
代碼在IPCThreadState.cpp 356行
int64_t IPCThreadState::clearCallingIdentity()
{
int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
clearCaller();
return token;
}
UID和PID是IPCThreadState的成員變量,都是32位的int型數據,通過移動操作,將UID和PID的信息保存到token,其中高32位保存UID,低32位保存PID。然后調用clearCaller()方法將當前本地進程pid和uid分別賦值給PID和UID,這個具體的操作在IPCThreadState::clearCaller()里面,最后返回token
1.1.1、IPCThreadState::clearCaller()
代碼在IPCThreadState.cpp 356行
void IPCThreadState::clearCaller()
{
mCallingPid = getpid();
mCallingUid = getuid();
}
2、JNI:restoreCallingIdentity
代碼在android_util_Binder.cpp 776行
static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, jlong token)
{
// XXX temporary sanity check to debug crashes.
//token記錄著uid信息,將其右移32位得到的是uid
int uid = (int)(token>>32);
if (uid > 0 && uid < 999) {
// In Android currently there are no uids in this range.
//目前android系統不存在小于999的uid,所以uid<999則拋出異常。
char buf[128];
sprintf(buf, "Restoring bad calling ident: 0x%" PRIx64, token);
jniThrowException(env, "java/lang/IllegalStateException", buf);
return;
}
IPCThreadState::self()->restoreCallingIdentity(token);
}
這個方法主要是獲取uid,然后調用IPCThreadState的restoreCallingIdentity(token)方法
2.1、restoreCallingIdentity
代碼在IPCThreadState.cpp 383行
void IPCThreadState::restoreCallingIdentity(int64_t token)
{
mCallingUid = (int)(token>>32);
mCallingPid = (int)token;
}
從token中解析出PID和UID,并賦值給相應的變量。該方法正好是clearCallingIdentity反過程。
3、JNI:getCallingPid
代碼在android_util_Binder.cpp 761行
static jint android_os_Binder_getCallingPid(JNIEnv* env, jobject clazz)
{
return IPCThreadState::self()->getCallingPid();
}
調用的是IPCThreadState的getCallingPid()方法
3.1、IPCThreadState::getCallingPid
代碼在IPCThreadState.cpp 346行
pid_t IPCThreadState::getCallingPid() const
{
return mCallingPid;
}
直接返回mCallingPid
4、JNI:getCallingUid
代碼在android_util_Binder.cpp 766行
static jint android_os_Binder_getCallingUid(JNIEnv* env, jobject clazz)
{
return IPCThreadState::self()->getCallingUid();
}
調用的是IPCThreadState的getCallingUid()方法
4.1、IPCThreadState::getCallingUid
代碼在IPCThreadState.cpp 346行
uid_t IPCThreadState::getCallingUid() const
{
return mCallingUid;
}
直接返回mCallingUid
5、遠程調用
5.1、binder_thread_read
代碼在binder.c 的2654行
binder_thread_read(){
...
while (1) {
struct binder_work *w;
switch (w->type) {
case BINDER_WORK_TRANSACTION:
t = container_of(w, struct binder_transaction, work);
break;
case :...
}
if (!t)
continue; //只有BR_TRANSACTION,BR_REPLY才會往下執行
tr.code = t->code;
tr.flags = t->flags;
tr.sender_euid = t->sender_euid; //mCallingUid
if (t->from) {
struct task_struct *sender = t->from->proc->tsk;
//當非oneway的情況下,將調用者進程的pid保存到sender_pid
tr.sender_pid = task_tgid_nr_ns(sender,current->nsproxy->pid_ns);
} else {
//當oneway的的情況下,則該值為0
tr.sender_pid = 0;
}
...
}
5.2、IPCThreadState. executeCommand()
代碼在IPCThreadState.cpp 的947行
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_TRANSACTION:
{
const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid;
// 設置調用者pid
mCallingPid = tr.sender_pid;
// 設置調用者uid
mCallingUid = tr.sender_euid;
...
reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
// 恢復原來的pid
mCallingPid = origPid;
// 恢復原來的uid
mCallingUid = origUid;
}
case :...
}
}
關于mCallingPid、mCallingUid修改過程:是在每次Binder Call的遠程進程在執行binder_thread_read()過程中,會設置pid和uid,然后在IPCThreadState的transact收到BR_TRANSACTION則會修改mCallingPid,mCallingUid。
PS:當oneway的情況下:mCallingPid=0,不過mCallingUid可以拿到正確值
(三) 思考
1、場景分析:
(1)場景:比如線程X通過Binder遠程調用線程Y,然后線程Y通過Binder調用當前線程的另一個Service或者activity之類的組件。
(2)分析:
- 1 線程X通過Binder遠程調用線程Y:則線程Y的IPCThreadState中的mCallingUid和mCallingPid保存的就是線程X的UID和PID。這時在線程Y中調用Binder.getCallingPid()和Binder.getCallingUid()方法便可獲取線程X的UID和PID,然后利用UID和PID進行權限對比,判斷線程X是否有權限調用線程Y的某個方法
- 2 線程Y通過Binder調用當前線程的某個組件:此時線程Y是線程Y某個組件的調用端,則mCallingUid和mCallingPid應該保存當前線程Y的PID和UID,故需要調用clearCallingIdentity()方法完成這個功能。當前線程Y調用完某個組件,由于線程Y仍然處于線程A的被用調用端,因此mCallingUidh和mCallingPid需要回復線程A的UID和PID,這時調用restoreCallingIdentity()即完成。
一句話:圖中過程2(調用組件2開始之前)執行clearCallingIdentity(),過程3(調用組件2結束之后)執行restoreCallingIdentity()。
2、實例分析:
上述過程主要在system_server進程各個線程中比較常見(普通app應用很少出現),比如system_server進程中的ActivityManagerService子線程
代碼在ActivityManagerService.java 6246行
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
//獲取遠程Binder調用端的pid
int callingPid = Binder.getCallingPid();
// 清除遠程Binder調用端的uid和pid信息,并保存到origId變量
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
//通過origId變量,還原遠程Binder調用端的uid和pid信息
Binder.restoreCallingIdentity(origId);
}
}
attachApplication()該方法一般是system_server進程的子線程調用遠程進程時使用,而attachApplicationLocked()方法則在同一個線程中,故需要在調用該方法前清空遠程調用該方法清空遠程調用者的uid和pid,調用結束后恢復遠程調用者的uid和pid。
三、Binder的死亡通知機制
(一)、概述
死亡通知時為了讓Bp端(客戶端進程)能知曉Bn端(服務端進程)的生死情況,當Bn進程死亡后能通知到Bp端。
- 定義:AppDeathRecipient是繼承IBinder::DeathRecipient類,主要需要實現其binderDied()來進行死亡通告。
- 注冊:binder->linkToDeath(AppDeathRecipient)是為了將AppDeathRecipient死亡通知注冊到Binder上
Bn端只需要重寫binderDied()方法,實現一些后尾清楚類的工作,則在Bn端死掉后,會回調binderDied()進行相應處理。
(二)、注冊死亡通知
1、Java層代碼
代碼在ActivityManagerService.java 6016行
public final class ActivityManagerService {
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
...
//創建IBinder.DeathRecipient子類對象
AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);
//建立binder死亡回調
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
...
//取消binder死亡回調
app.unlinkDeathRecipient();
}
private final class AppDeathRecipient implements IBinder.DeathRecipient {
...
public void binderDied() {
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true);
}
}
}
}
這里面涉及兩個方法linkToDeath和unlinkToDeath方法,實現如下:
1.1、linkToDeath()與unlinkToDeath()
代碼在ActivityManagerService.java 397行
public class Binder implements IBinder {
public void linkToDeath(DeathRecipient recipient, int flags) {
}
public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
return true;
}
}
代碼在ActivityManagerService.java 509行
final class BinderProxy implements IBinder {
public native void linkToDeath(DeathRecipient recipient, int flags)
throws RemoteException;
public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
}
可見,以上兩個方法:
- 當為Binder服務端,則相應的兩個方法實現為空,沒有實際功能;
- 當為BinderProxy代理端,則調用native方法來實現相應功能,這是真實使用場景
2、JNI及Native層代碼
native方法linkToDeath()和unlinkToDeath() 通過JNI實現,我們來依次了解。
2.1 android_os_BinderProxy_linkToDeath()
代碼在android_util_Binder.cpp 397行
static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj,
jobject recipient, jint flags)
{
if (recipient == NULL) {
jniThrowNullPointerException(env, NULL);
return;
}
//第一步 獲取BinderProxy.mObject成員變量值, 即BpBinder對象
IBinder* target = (IBinder*)env->GetLongField(obj, gBinderProxyOffsets.mObject);
...
//只有Binder代理對象才會進入該對象
if (!target->localBinder()) {
DeathRecipientList* list = (DeathRecipientList*)
env->GetLongField(obj, gBinderProxyOffsets.mOrgue);
//第二步 創建JavaDeathRecipient對象
sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient, list);
//第三步 建立死亡通知
status_t err = target->linkToDeath(jdr, NULL, flags);
if (err != NO_ERROR) {
//如果添加失敗,第四步 , 則從list移除引用
jdr->clearReference();
signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/);
}
}
}
大體流程是:
- 第一步,獲取BpBinder對象
- 第二步,構建JavaDeathRecipient對象
- 第三步,調用BpBinder的linkToDeath,建立死亡通知
- 第四步,如果添加死亡通知失敗,則調用JavaDeathRecipient的clearReference移除
補充說明:
- 獲取DeathRecipientList:其成員變量mList記錄該BinderProxy的JavaDeathRecipient列表信息(一個BpBinder可以注冊多個死亡回調)
- 創建JavaDeathRecipient:繼承與IBinder::DeathRecipient
那我們就依照上面四個步驟依次詳細了解下,獲取BpBinder對象的過程和之前講解Binder一樣,這里就不詳細說明了,直接從第二步開始。
2.1.1 JavaDeathRecipient類
代碼在android_util_Binder.cpp 348行
class JavaDeathRecipient : public IBinder::DeathRecipient
{
public:
JavaDeathRecipient(JNIEnv* env, jobject object, const sp<DeathRecipientList>& list)
: mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
mObjectWeak(NULL), mList(list)
{
//將當前對象sp添加到列表DeathRecipientList
list->add(this);
android_atomic_inc(&gNumDeathRefs);
incRefsCreated(env);
}
}
該方法主要功能:
- 通過env->NewGloablRef(object),為recipient創建相應的全局引用,并保存到mObject成員變量
- 將當前對象JavaDeathRecipient強指針sp添加到DeathRecipientList
這里說下DeathRecipient關系圖
其中Java層的BinderProxy.mOrgue 指向DeathRecipientList,而DeathRecipientList記錄JavaDeathRecipient對象
最后調用了incRefsCreated()函數,讓我們來看下
2.1.1.1 incRefsCreated()函數
代碼在android_util_Binder.cpp 144行
static void incRefsCreated(JNIEnv* env)
{
int old = android_atomic_inc(&gNumRefsCreated);
if (old == 200) {
android_atomic_and(0, &gNumRefsCreated);
//出發forceGc
env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
gBinderInternalOffsets.mForceGc);
} else {
ALOGV("Now have %d binder ops", old);
}
}
該方法的主要作用是增加引用計數incRefsCreated,每計數增加200則執行一次forceGC;
會觸發調用incRefsCreated()的場景有:
- JavaBBinder 對象創建過程
- JavaDeathRecipient對象創建過程
- javaObjectForIBinder()方法:將native層的BpBinder對象轉換為Java層BinderProxy對象的過程
2.1.2 BpBinder::linkToDeath()
代碼在BpBinder.cpp 173行
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
Obituary ob;
//recipient 該對象為JavaDeathRecipient
ob.recipient = recipient;
// cookie 為null
ob.cookie = cookie;
// flags=0;
ob.flags = flags;
LOG_ALWAYS_FATAL_IF(recipient == NULL,
"linkToDeath(): recipient must be non-NULL");
{
AutoMutex _l(mLock);
if (!mObitsSent) {
// 沒有執行過sendObituary,則進入該方法
if (!mObituaries) {
mObituaries = new Vector<Obituary>;
if (!mObituaries) {
return NO_MEMORY;
}
ALOGV("Requesting death notification: %p handle %d\n", this, mHandle);
getWeakRefs()->incWeak(this);
IPCThreadState* self = IPCThreadState::self();
//具體調用步驟1
self->requestDeathNotification(mHandle, this);
// 具體調用步驟2
self->flushCommands();
}
// 將創新的Obituary添加到mbituaries
ssize_t res = mObituaries->add(ob);
return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
}
}
return DEAD_OBJECT;
}
這里面的核心代碼的就是分別調用了** IPCThreadState的requestDeathNotification(mHandle, this)函數和flushCommands()**函數,那我們就一次來看下
2.1.2.1 IPCThreadState::requestDeathNotification()函數
代碼在BpBinder.cpp 670行
status_t IPCThreadState::requestDeathNotification(int32_t handle, BpBinder* proxy)
{
mOut.writeInt32(BC_REQUEST_DEATH_NOTIFICATION);
mOut.writeInt32((int32_t)handle);
mOut.writePointer((uintptr_t)proxy);
return NO_ERROR;
}
進入Binder Driver后,直接調用后進入binder_thread_write處理BC_REQUEST_DEATH_NOTIFICATION命令
2.1.2.2 IPCThreadState::flushCommands()函數
代碼在BpBinder.cpp 395行
void IPCThreadState::flushCommands()
{
if (mProcess->mDriverFD <= 0)
return;
talkWithDriver(false);
}
flushCommands就是把命令向驅動發出,此處參數是false,則不會阻塞等待讀。向Linux Kernel層的Binder Driver發送 BC_REQEUST_DEATH_NOTIFACTION命令,經過ioctl執行到binder_ioctl_write_read()方法。
2.1.3 clearReference()函數
代碼在android_util_Binder.cpp 412行
void clearReference()
{
sp<DeathRecipientList> list = mList.promote();
if (list != NULL) {
// 從列表中移除
list->remove(this);
}
}
3、Linux Kernel層代碼
3.1、binder_ioctl_write_read()函數
代碼在binder.c 3138行
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
// 把用戶控件數據ubuf拷貝到bwr
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
// 此時寫入緩存數據
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
...
}
//此時讀緩存沒有數據
if (bwr.read_size > 0) {
...
}
// 將內核數據bwr拷貝到用戶控件ubuf
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
主要調用binder_thread_write來讀寫緩存數據,按我們來看下binder_thread_write()函數
3.2、binder_thread_write()函數
代碼在binder.c 2252行
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
//proc, thread都是指當前發起端進程的信息
struct binder_context *context = proc->context;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
get_user(cmd, (uint32_t __user *)ptr); //獲取BC_REQUEST_DEATH_NOTIFICATION
ptr += sizeof(uint32_t);
switch (cmd) {
case BC_REQUEST_DEATH_NOTIFICATION:{
//注冊死亡通知
uint32_t target;
void __user *cookie;
struct binder_ref *ref;
struct binder_ref_death *death;
//獲取targe
get_user(target, (uint32_t __user *)ptr); t
ptr += sizeof(uint32_t);
//獲取BpBinder
get_user(cookie, (void __user * __user *)ptr);
ptr += sizeof(void *);
//拿到目標服務的binder_ref
ref = binder_get_ref(proc, target);
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
//native Bp可注冊多個,但Kernel只允許注冊一個死亡通知
if (ref->death) {
break;
}
death = kzalloc(sizeof(*death), GFP_KERNEL);
INIT_LIST_HEAD(&death->work.entry);
death->cookie = cookie;
ref->death = death;
//當目標binder服務所在進程已死,則直接發送死亡通知。這是非常規情況
if (ref->node->proc == NULL) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
//當前線程為binder線程,則直接添加到當前線程的todo隊列.
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&ref->death->work.entry, &thread->todo);
} else {
list_add_tail(&ref->death->work.entry, &proc->todo);
wake_up_interruptible(&proc->wait);
}
}
} else {
...
}
} break;
case ...;
}
*consumed = ptr - buffer;
}
}
該方法在處理BC_REQUEST_DEATH_NOTIFACTION過程,正好遇到目標Binder進服務所在進程已死的情況,向todo隊列增加BINDER_WORK_BINDER事務,直接發送死亡通知,但這屬于非常規情況。
更常見的場景是binder服務所在進程死亡后,會調用binder_release方法,然后調用binder_node_release。這個過程便會發出死亡通知的回調。
(三)、出發死亡通知
當Binder服務所在進程死亡后,會釋放進程相關的資源,Binder也是一種資源。binder_open打開binder驅動/dev/binder,這是字符設備,獲取文件描述符。在進程結束的時候會有一個關閉文件系統的過程會調用驅動close方法,該方法相對應的是release()方法。當binder的fd被釋放后,此處調用相應的方法是binder_release()。
但并不是每個close系統調用都會出發調用release()方法。只有真正釋放設備數據結構才調用release(),內核維持一個文件結構被使用多少次的技術,即便是應用程序沒有明顯地關閉它打開的文件也使用:內核在進程exit()時會釋放所有內存和關閉相應的文件資源,通過使用close系統調用最終也會release binder。
1、release
代碼在binder.c 4172行
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.compat_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
//對應著release的方法
.release = binder_release,
};
那我們來看下binder_release
2、binder_release
代碼在binder.c 3536行
static int binder_release(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc = filp->private_data;
debugfs_remove(proc->debugfs_entry);
binder_defer_work(proc, BINDER_DEFERRED_RELEASE);
return 0;
}
我們看到里面調用了binder_defer_work()函數,那我們一起繼續看下
3、binder_defer_work
代碼在binder.c 3739行
static void
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer)
{
//獲取鎖
mutex_lock(&binder_deferred_lock);
// 添加BINDER_DEFERRED_RELEASE
proc->deferred_work |= defer;
if (hlist_unhashed(&proc->deferred_work_node)) {
hlist_add_head(&proc->deferred_work_node,
&binder_deferred_list);
//向工作隊列添加binder_derred_work
schedule_work(&binder_deferred_work);
}
// 釋放鎖
mutex_unlock(&binder_deferred_lock);
}
這里面涉及到一個結構體binder_deferred_workqueue,那我們就來看下
4、binder_deferred_workqueue
代碼在binder.c 3737行
static DECLARE_WORK(binder_deferred_work, binder_deferred_func);
代碼在workqueue.h 183行
#define DECLARE_WORK(n, f) \
struct work_struct n = __WORK_INITIALIZER(n, f)
代碼在workqueue.h 169行
#define __WORK_INITIALIZER(n, f) { \
.data = WORK_DATA_STATIC_INIT(), \
.entry = { &(n).entry, &(n).entry }, \
.func = (f), \
__WORK_INIT_LOCKDEP_MAP(#n, &(n)) \
}
上面看起來有點凌亂,那我們合起來看
static DECLARE_WORK(binder_deferred_work, binder_deferred_func);
#define DECLARE_WORK(n, f) \
struct work_struct n = __WORK_INITIALIZER(n, f)
#define __WORK_INITIALIZER(n, f) { \
.data = WORK_DATA_STATIC_INIT(), \
.entry = { &(n).entry, &(n).entry }, \
.func = (f), \
__WORK_INIT_LOCKDEP_MAP(#n, &(n)) \
}
那么 他是什么時候被初始化的?
代碼在binder.c 4215行
//全局工作隊列
static struct workqueue_struct *binder_deferred_workqueue;
static int __init binder_init(void)
{
int ret;
//創建了名叫“binder”的工作隊列
binder_deferred_workqueue = create_singlethread_workqueue("binder");
if (!binder_deferred_workqueue)
return -ENOMEM;
...
}
device_initcall(binder_init);
在Binder設備驅動初始化過程中執行binder_init()方法中,調用create_singlethread_workqueue(“binder”),創建了名叫"binder"的工作隊列(workqueue)。workqueue是kernel提供的一種實現簡單而有效的內核線程機制,可延遲執行任務。
此處的binder_deferred_work的func為binder_deferred_func,接下來看該方法。
5、binder_deferred_work
代碼在binder.c 2697行
static void binder_deferred_func(struct work_struct *work)
{
struct binder_proc *proc;
struct files_struct *files;
int defer;
do {
binder_lock(__func__);
// 獲取binder_main_lock
mutex_lock(&binder_deferred_lock);
if (!hlist_empty(&binder_deferred_list)) {
proc = hlist_entry(binder_deferred_list.first,
struct binder_proc, deferred_work_node);
hlist_del_init(&proc->deferred_work_node);
defer = proc->deferred_work;
proc->deferred_work = 0;
} else {
proc = NULL;
defer = 0;
}
mutex_unlock(&binder_deferred_lock);
files = NULL;
if (defer & BINDER_DEFERRED_PUT_FILES) {
files = proc->files;
if (files)
proc->files = NULL;
}
if (defer & BINDER_DEFERRED_FLUSH)
binder_deferred_flush(proc);
if (defer & BINDER_DEFERRED_RELEASE)
// 核心代碼,調用binder_deferred_release()
binder_deferred_release(proc); /* frees proc */
binder_unlock(__func__);
if (files)
put_files_struct(files);
} while (proc);
}
可見,binder_release最終調用的是binder_deferred_release;同理,binder_flush最終調用的是binder_deferred_flush。
6、binder_deferred_release
代碼在binder.c 3590行
static void binder_deferred_release(struct binder_proc *proc)
{
struct binder_transaction *t;
struct binder_context *context = proc->context;
struct rb_node *n;
int threads, nodes, incoming_refs, outgoing_refs, buffers,
active_transactions, page_count;
BUG_ON(proc->vma);
BUG_ON(proc->files);
//刪除proc_node節點
hlist_del(&proc->proc_node);
if (context->binder_context_mgr_node &&
context->binder_context_mgr_node->proc == proc) {
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"%s: %d context_mgr_node gone\n",
__func__, proc->pid);
context->binder_context_mgr_node = NULL;
}
//釋放binder_thread
threads = 0;
active_transactions = 0;
while ((n = rb_first(&proc->threads))) {
struct binder_thread *thread;
thread = rb_entry(n, struct binder_thread, rb_node);
threads++;
active_transactions += binder_free_thread(proc, thread);
}
//釋放binder_node
nodes = 0;
incoming_refs = 0;
while ((n = rb_first(&proc->nodes))) {
struct binder_node *node;
node = rb_entry(n, struct binder_node, rb_node);
nodes++;
rb_erase(&node->rb_node, &proc->nodes);
incoming_refs = binder_node_release(node, incoming_refs);
}
//釋放binder_ref
outgoing_refs = 0;
while ((n = rb_first(&proc->refs_by_desc))) {
struct binder_ref *ref;
ref = rb_entry(n, struct binder_ref, rb_node_desc);
outgoing_refs++;
binder_delete_ref(ref);
}
//釋放binder_work
binder_release_work(&proc->todo);
binder_release_work(&proc->delivered_death);
buffers = 0;
while ((n = rb_first(&proc->allocated_buffers))) {
struct binder_buffer *buffer;
buffer = rb_entry(n, struct binder_buffer, rb_node);
t = buffer->transaction;
if (t) {
t->buffer = NULL;
buffer->transaction = NULL;
pr_err("release proc %d, transaction %d, not freed\n",
proc->pid, t->debug_id);
/*BUG();*/
}
//釋放binder_buf
binder_free_buf(proc, buffer);
buffers++;
}
binder_stats_deleted(BINDER_STAT_PROC);
page_count = 0;
if (proc->pages) {
int i;
for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) {
void *page_addr;
if (!proc->pages[i])
continue;
page_addr = proc->buffer + i * PAGE_SIZE;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%s: %d: page %d at %p not freed\n",
__func__, proc->pid, i, page_addr);
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
__free_page(proc->pages[i]);
page_count++;
}
kfree(proc->pages);
vfree(proc->buffer);
}
put_task_struct(proc->tsk);
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n",
__func__, proc->pid, threads, nodes, incoming_refs,
outgoing_refs, active_transactions, buffers, page_count);
kfree(proc);
}
此處proc是來自Bn端的binder_proc.
binder_defered_release的主要工作有:
- binder_free_thread(proc,thread)
- binder_node_release(node,incoming_refs)
- binder_delete_ref(ref)
-binder_release_work(&proc->todo)
-binder_release_work(&proc->delivered_death)
-binder_free_buff(proc,buffer)
-以及釋放各種內存信息
6.1、binder_free_thread
代碼在binder.c 3065行
static int binder_free_thread(struct binder_proc *proc,
struct binder_thread *thread)
{
struct binder_transaction *t;
struct binder_transaction *send_reply = NULL;
int active_transactions = 0;
rb_erase(&thread->rb_node, &proc->threads);
t = thread->transaction_stack;
if (t && t->to_thread == thread)
send_reply = t;
while (t) {
active_transactions++;
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"release %d:%d transaction %d %s, still active\n",
proc->pid, thread->pid,
t->debug_id,
(t->to_thread == thread) ? "in" : "out");
if (t->to_thread == thread) {
t->to_proc = NULL;
t->to_thread = NULL;
if (t->buffer) {
t->buffer->transaction = NULL;
t->buffer = NULL;
}
t = t->to_parent;
} else if (t->from == thread) {
t->from = NULL;
t = t->from_parent;
} else
BUG();
}
//發送失敗回復
if (send_reply)
binder_send_failed_reply(send_reply, BR_DEAD_REPLY);
binder_release_work(&thread->todo);
kfree(thread);
binder_stats_deleted(BINDER_STAT_THREAD);
return active_transactions;
}
6.2、binder_node_release
代碼在binder.c 3546行
static int binder_node_release(struct binder_node *node, int refs)
{
struct binder_ref *ref;
int death = 0;
list_del_init(&node->work.entry);
binder_release_work(&node->async_todo);
if (hlist_empty(&node->refs)) {
//引用為空,直接刪除節點
kfree(node);
binder_stats_deleted(BINDER_STAT_NODE);
return refs;
}
node->proc = NULL;
node->local_strong_refs = 0;
node->local_weak_refs = 0;
hlist_add_head(&node->dead_node, &binder_dead_nodes);
hlist_for_each_entry(ref, &node->refs, node_entry) {
refs++;
if (!ref->death)
continue;
death++;
if (list_empty(&ref->death->work.entry)) {
//添加BINDER_WORK_DEAD_BINDER事務到todo隊列
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
list_add_tail(&ref->death->work.entry,
&ref->proc->todo);
wake_up_interruptible(&ref->proc->wait);
} else
BUG();
}
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"node %d now dead, refs %d, death %d\n",
node->debug_id, refs, death);
return refs;
}
該方法會遍歷該binder_node所有的binder_ref,當存在binder希望通知,則向相應的binder_ref所在進程的todo隊列添加BINDER_WORK_DEAD_BINDER事務并喚醒處于proc->wait的binder線程。
6.3、binder_delete_ref
代碼在binder.c 1133行
static void binder_delete_ref(struct binder_ref *ref)
{
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d delete ref %d desc %d for node %d\n",
ref->proc->pid, ref->debug_id, ref->desc,
ref->node->debug_id);
rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc);
rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node);
if (ref->strong)
binder_dec_node(ref->node, 1, 1);
hlist_del(&ref->node_entry);
binder_dec_node(ref->node, 0, 1);
if (ref->death) {
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"%d delete ref %d desc %d has death notification\n",
ref->proc->pid, ref->debug_id, ref->desc);
list_del(&ref->death->work.entry);
kfree(ref->death);
binder_stats_deleted(BINDER_STAT_DEATH);
}
kfree(ref);
binder_stats_deleted(BINDER_STAT_REF);
}
6.4、binder_delete_ref
代碼在binder.c 2980行
static void binder_release_work(struct list_head *list)
{
struct binder_work *w;
while (!list_empty(list)) {
w = list_first_entry(list, struct binder_work, entry);
//刪除 binder_work
list_del_init(&w->entry);
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
struct binder_transaction *t;
t = container_of(w, struct binder_transaction, work);
if (t->buffer->target_node &&
!(t->flags & TF_ONE_WAY)) {
//發送failed回復
binder_send_failed_reply(t, BR_DEAD_REPLY);
} else {
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"undelivered transaction %d\n",
t->debug_id);
t->buffer->transaction = NULL;
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
} break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"undelivered TRANSACTION_COMPLETE\n");
kfree(w);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
} break;
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
struct binder_ref_death *death;
death = container_of(w, struct binder_ref_death, work);
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"undelivered death notification, %016llx\n",
(u64)death->cookie);
kfree(death);
binder_stats_deleted(BINDER_STAT_DEATH);
} break;
default:
pr_err("unexpected work type, %d, not freed\n",
w->type);
break;
}
}
}
6.4、binder_delete_ref
代碼在binder.c 2980行
static void binder_free_buf(struct binder_proc *proc,
struct binder_buffer *buffer)
{
size_t size, buffer_size;
buffer_size = binder_buffer_size(proc, buffer);
size = ALIGN(buffer->data_size, sizeof(void *)) +
ALIGN(buffer->offsets_size, sizeof(void *)) +
ALIGN(buffer->extra_buffers_size, sizeof(void *));
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_free_buf %p size %zd buffer_size %zd\n",
proc->pid, buffer, size, buffer_size);
BUG_ON(buffer->free);
BUG_ON(size > buffer_size);
BUG_ON(buffer->transaction != NULL);
BUG_ON((void *)buffer < proc->buffer);
BUG_ON((void *)buffer > proc->buffer + proc->buffer_size);
if (buffer->async_transaction) {
proc->free_async_space += size + sizeof(struct binder_buffer);
binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
"%d: binder_free_buf size %zd async free %zd\n",
proc->pid, size, proc->free_async_space);
}
binder_update_page_range(proc, 0,
(void *)PAGE_ALIGN((uintptr_t)buffer->data),
(void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK),
NULL);
rb_erase(&buffer->rb_node, &proc->allocated_buffers);
buffer->free = 1;
if (!list_is_last(&buffer->entry, &proc->buffers)) {
struct binder_buffer *next = list_entry(buffer->entry.next,
struct binder_buffer, entry);
if (next->free) {
rb_erase(&next->rb_node, &proc->free_buffers);
binder_delete_free_buffer(proc, next);
}
}
if (proc->buffers.next != &buffer->entry) {
struct binder_buffer *prev = list_entry(buffer->entry.prev,
struct binder_buffer, entry);
if (prev->free) {
binder_delete_free_buffer(proc, buffer);
rb_erase(&prev->rb_node, &proc->free_buffers);
buffer = prev;
}
}
binder_insert_free_buffer(proc, buffer);
}
(四)、總結
對于Binder IPC進程都會打開/dev/binder文件,當進程異常退出時,Binder驅動會保證釋放將要退出的進程中沒有正常關閉的/dev/binder文件,實現機制是binder驅動通過調用/dev/binder文件所在對應的release回調函數,執行清理工作,并且檢查BBinder是否注冊死亡通知,當發現存在死亡通知時,就向其對應的BpBinder端發送死亡通知消息。
死亡回調DeathRecipient只有Bp才能正確使用,因為DeathRecipient用于監控Bn掛掉的情況,如果Bn建立跟自己的死亡通知,自己進程都掛了,就無法通知了。
清空引用,將JavaDeathRecipient從DeathRecipientList列表移除。