---
title: 'Binder - Native SeriveManager'
disqus: kyleAlien
---
Binder - Native SeriveManager
===
## OverView of Content
ServiceManager 啟動是 [**Android 啟動**](https://hackmd.io/pJpAeKAeRea0VIW3oI-mXw?view) 的一部分
[TOC]
## SeriveManager 啟動
簡單來說就是 啟動 init 進程,init 進程分析 init.rc 檔案,並啟動新進程
> 
* 從 [**init.rc**](https://android.googlesource.com/platform/system/core/+/master/rootdir/init.rc#448) 的 `on init` (action) 可以看到它最後啟動了 ServiceManager 服務進程,而啟動 ServiceManager 會先啟動到 [**servicemanager.rc**](https://android.googlesource.com/platform/frameworks/native/+/master/cmds/servicemanager/servicemanager.rc) (真正啟動服務)
```shell=
# /rootdir/init.rc 檔案
on init
...
# Start essential services. # essential 基礎
start servicemanager # 啟動 srvicemanager.rc
start hwservicemanager
start vndservicemanager
# -----------------------------------------------------------------------
# /cmds/servicemanager/servicemanager.rc
# service 格式:service <name> <pathname>
service servicemanager /system/bin/servicemanager # 啟動 servicemanager
class core animation # 所屬的 class 為 animation
user system # 以用戶 sustem 的身份運行
group system readproc
critical # 若失敗 4 次則進入恢復模式
# 若重新啟動則需要 重起以下服務 (onrestart)
onrestart restart apexd
onrestart restart audioserver
onrestart restart gatekeeperd
onrestart class_restart main
onrestart class_restart hal
onrestart class_restart early_hal
writepid /dev/cpuset/system-background/tasks
shutdown critical
```
* init 進程分析完 `servicemanager.rc` 後,才會啟動 ServiceManager 的 [**Android.bp**](https://android.googlesource.com/platform/frameworks/native/+/master/cmds/servicemanager/Android.bp) 檔案
:::info
* Android 最新的啟動由 Android.mk 檔案,改成 **Android.bp** 檔案
:::
```shell=
## /servicemanager/Android.bp
cc_defaults {
name: "servicemanager_defaults",
cflags: [
"-Wall",
"-Wextra",
"-Werror",
"-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
srcs: [
"Access.cpp",
"ServiceManager.cpp", // 啟動檔案
],
shared_libs: [
"libbase",
"libbinder", // 依賴 binder 動態檔案
"libvintf",
"libcutils",
"liblog",
"libutils",
"libselinux",
],
target: {
vendor: {
exclude_shared_libs: ["libvintf"],
},
},
}
## 依賴 lib
## 重點啟動 servicemanager#main
cc_binary {
name: "servicemanager",
defaults: ["servicemanager_defaults"], // 預設啟動配置
init_rc: ["servicemanager.rc"],
srcs: ["main.cpp"],
}
... 省略部份
```
* 透過上面 `Android.dp` 檔案,可以知道它將會啟動 `servicemanager#main.cpp` 檔案
### [ServiceManager](https://android.googlesource.com/platform/frameworks/native/+/master/cmds/servicemanager/main.cpp) - main 函數
* `servicemanager#main` 函數:先來了解一下使用到的重要類、還有其方法
| 類 | 重點函數 | 功能 |
| -------- | -------- | -------- |
| ProcessState | initWithDriver | 開啟 `/dev/binder` 裝置 |
| ProcessState | becomeContextManager | 將當前進程設定為 Binder 管理者 |
| Looper | prepare | 準備 Looper,並設定可接受 callback |
| Looper | pollAll | 等待客戶請求 |
1. **`ProcessState::initWithDriver` 函數**:初始化,開啟指定設備(預設為 `/dev/binder` 裝置),映射到自身 (ServiceManager) 進程
```cpp=
// /servicemanager/main.cpp
int main(int argc, char** argv) {
...
// 判斷輸入參數,不可大於 2 個
if (argc > 2) {
LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
}
// 目標開啟文件,預設為 "/dev/binder"
const char* driver = argc == 2 ? argv[1] : "/dev/binder";
// ProcessState 為進程單例
// @ initWithDriver
sp<ProcessState> ps = ProcessState::initWithDriver(driver);
...
return EXIT_FAILURE;
}
```
2. ProcessState (也就是 ServiceManager) 設定最大 Thread 數量為 0、並 **將自身設定為 "manager" 並註冊到列表中**
```cpp=
// /servicemanager/main.cpp
int main(int argc, char** argv) {
... 開啟 /dev/binder
// 設定 Binder thread 上限為 0
ps->setThreadPoolMaxThreadCount(0);
ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
// 創建 ServiceManager 實例
sp<ServiceManager> manager =
sp<ServiceManager>::make(std::make_unique<Access>());
if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
LOG(ERROR) << "Could not self register servicemanager";
}
...
return EXIT_FAILURE;
}
```
3. 將自身設定為 Binder 管理者
```cpp=
// /servicemanager/main.cpp
int main(int argc, char** argv) {
...
// 設定 ServiceManager 處理 Binder 訊息
IPCThreadState::self()->setTheContextObject(manager);
// @becomeContextManager 將當前進程設定為 Binder 管理者
ps->becomeContextManager();
...
return EXIT_FAILURE;
}
```
4. 啟動 Looper,開始監聽 Binder 事件
```cpp=
// /servicemanager/main.cpp
int main(int argc, char** argv) {
...
// 啟動 Looper
sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
BinderCallback::setupTo(looper);
ClientCallbackCallback::setupTo(looper, manager);
// Looper 進入循環監聽
while(true) {
looper->pollAll(-1);
}
return EXIT_FAILURE;
}
```
### [**binder_open**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c) - 開啟 binder 文件
* [**ProcessState**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/ProcessState.cpp)::**initWithDriver**:開啟目標文件,若是沒指定則開啟 `/dev/binder` 文件
```cpp=
// ProcessState.cpp
// 傳入 driver 為 "/dev/binder"
sp<ProcessState> ProcessState::initWithDriver(const char* driver)
{
return init(driver, true /*requireDefault*/);
}
sp<ProcessState> ProcessState::init(const char *driver,
bool requireDefault)
{
#ifdef BINDER_IPC_32BIT
log... 當前啟動方式不適用 32 bit 裝置
#endif
if (driver == nullptr) {
std::lock_guard<std::mutex> l(gProcessMutex);
if (gProcess) {
verifyNotForked(gProcess->mForked);
}
return gProcess;
}
// 單例呼叫
[[clang::no_destroy]] static std::once_flag gProcessOnce;
std::call_once(gProcessOnce, [&](){
// 嘗試訪問目標裝置
if (access(driver, R_OK) == -1) {
ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
// 如果訪問失敗,則轉為 預設 /dev/binder
driver = "/dev/binder";
}
// 在實例化 ProcessState 之前先進行一些處理
int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
ProcessState::childPostFork);
... log 訊息
std::lock_guard<std::mutex> l(gProcessMutex);
gProcess = sp<ProcessState>::make(driver);
});
... log 訊息
verifyNotForked(gProcess->mForked);
return gProcess;
}
```
* ProcessState 初始化 (建構函數) 請參考 [**ProcessState**](https://hackmd.io/_8ne10VrSK-mK6nlyxL5RQ?view#%E9%80%B2%E7%A8%8B%E5%96%AE%E4%BE%8B-ProcessState),這邊大概說明一下
1. ProcessState 透過 open 開啟 `/dev/binder` 裝置 (或指定裝置)
2. 再透過 mmap 讓當前進程映射 binder 裝置 (下一小結說明)
* ProcessState#open 函數會呼叫到通過 systemcall 調用到 Kernel 空間的 [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c)#**binder_open 函數**
| 類 | 運行空間 | 對應函數 |
| -------- | -------- | -------- |
| ProcessState.cpp | User space | open |
| binder.c | Kernel space | binder_open |
:::success
* Kernel open 請參考 [**binder_open**](https://hackmd.io/_8ne10VrSK-mK6nlyxL5RQ?view#ProcessState---open-%E9%96%8B%E5%95%9F-Binder) 分析
:::
### [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c) - mmap 映射
* [**ProcessState**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/ProcessState.cpp) 建構函數會呼叫 [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c)#**mmap 函數** 開啟內存映射
| 類 | 運行空間 | 函數 |
| -------- | -------- | -------- |
| ProcessState.cpp | User space | mmap |
| binder.c | Kernel space | binder_mmap |
```cpp=
// ProcessState.cpp
ProcessState::ProcessState(const char* driver)
: mDriverName(String8(driver)),
mDriverFD(-1),
mVMStart(MAP_FAILED),
mThreadCountLock(PTHREAD_MUTEX_INITIALIZER),
mThreadCountDecrement(PTHREAD_COND_INITIALIZER),
/* 省略部份*/) {
// 開啟 /dev/binder 裝置
base::Result<int> opened = open_driver(driver);
if (opened.ok()) {
// mmap binder,提供一塊虛擬地址空間來接收事務
// 取得 mmap 後進程的虛擬地址
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
opened.value(), 0);
if (mVMStart == MAP_FAILED) {
... 省略失敗處理
}
}
...
if (opened.ok()) {
// 儲存 Binder 驅動偏移量
mDriverFD = opened.value();
}
}
```
:::success
* Kernel mmap 請參考 [**binder_mmap**](https://hackmd.io/8E1AyMAgRzym3g6ktNV37Q?view#binder_mmap-%E6%A6%82%E8%BF%B0) 分析
:::
### [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c) - ioctl binder 通訊(BINDER_SET_CONTEXT_MGR)
:::info
ServiceManager 透過 `becomeContextManager` 將自身設定為 Binder 驅動管理者,在這之中就要傳送 `BINDER_SET_CONTEXT_MGR` 命令
:::
```c=
// binder.h
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
```
* [**ProcessState**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/ProcessState.cpp)::**becomeContextManager**:主要是 **透過 ioctl 函數發送**`BINDER_SET_CONTEXT_MGR` Binder 命令,將自身設定為 Binder 管理者
```cpp=
// ProcessState.cpp
bool ProcessState::becomeContextManager()
{
AutoMutex _l(mLock);
flat_binder_object obj {
.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
};
// mDriverFD 是 '/dev/binder' 的偏移量 (在 open 時就儲存)
// 1. 首先嘗試設定 安全傳輸
int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);
// fallback to original method
if (result != 0) {
// 失敗則使用 default 0
int unused = 0;
// 透過 @ ioctl 傳輸 BINDER_SET_CONTEXT_MGR 命令給 Binder
result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &unused);
}
... 省略失敗處理
return result == 0;
}
```
* ProcessState::`becomeContextManager` 最終會呼叫 [**binder**](https://elixir.bootlin.com/linux/latest/source/drivers/android/binder.c)#**`ioctl` 函數** 開始與 Binder kernel 通訊(對應函數是 `binder_ioctl`)
| 類 | 運行空間 | 函數 |
| -------- | -------- | -------- |
| ProcessState.cpp | User space | ioctl |
| binder.c | Kernel space | binder_ioctl |
* **binder_ioctl** 函數分析 ServiceManager 設定為 Binder 管理者
> 
1. 取出 App 進程的 **binder_proc** 變量 (proc 就是進程資訊),接著計算指令大小 (**透過 \_IOC_SIZE 宏**)
:::info
* binder_proc 在 Native 層表現就是 **ProcessState.cpp**
:::
```c=
// /drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp,
unsigned int cmd,
long arg)
{
int ret;
// 從 filp 中抽取 proc 變量,也就是 binder_open 中創建的實例
// private_data 的類型就是 binder_proc(進程資訊)
struct binder_proc *proc = filp->private_data; // ServiceManager 在 Kernel 的表示方式
struct binder_thread *thread;
// 命令大小
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
...
return ret;
}
```
2. **堵塞操作**:判斷當前進程是否需要掛起(`wait_event_interruptible` 函數決定),當前情況來說並不會掛起(binder_stop_on_user_error < 2 成立)
```c=
// /drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
...
// wait_event_interruptible 掛起調用者進程
// 滿足 binder_stop_on_user_error < 2 就不會將該進程掛起
ret = wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
if (ret)
goto err_unlocked;
...
err_unlocked:
trace_binder_ioctl_done(ret);
return ret;
}
```
3. **查看 proc 中的 threads 的鏈表是否添加了當前線程的節點**,若是沒有則創建 & 插入一個 thread 節點
:::info
proc 中的 threads 鏈表是 **按照 pid 大小做排序的**
:::
> 如果無法取得 binder_thread 它也會幫你創建一個 binder_thread
```c=
// /drivers/staging/android/binder.c
static int binder_stop_on_user_error;
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
...
binder_lock(__func__);
// 取得呼叫者的線程
thread = binder_get_thread(proc);
// 查看最終結果是否失敗
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
...
ret = 0;
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
binder_unlock(__func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
...
return ret;
}
```
4. **處理具體命令**:目前要把 ServiceManager 設定為 Binder 管理者,所以 **傳入的命令是 `BINDER_SET_CONTEXT_MGR_EXT` 命令**
:::success
讀取使用者空間的資料後會轉換為 `flat_binder_object` 結構,其中就儲存了
* cookie:BinderServer 虛擬空間的地址
* BinderServer 的弱計數 `weakref_type` 地址
:::
```c=
// /drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
// 自身進程核心 (proc) 的空間
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg; // User space 的資料
...
switch (cmd) {
case BINDER_SET_CONTEXT_MGR_EXT: {
struct flat_binder_object fbo;
// 把 User space 資料複製到 Kernel space
if (copy_from_user(&fbo, ubuf, sizeof(fbo))) { // ubuf 中的資料複製到 fbo 結構中
ret = -EINVAL;
goto err;
}
// @ 追蹤 binder_ioctl_set_ctx_mgr
ret = binder_ioctl_set_ctx_mgr(filp, &fbo);
if (ret)
goto err;
break;
}
...
return ret;
}
```
5. 將當前 uid 設定給 servicemanager 進程(如果已經被設定過,則會判斷 uid 是否相同),並創建一個 **++binder node 節點 串接到 Kernel space 的紅黑數中++**
:::warning
裝置只允許有一個 BinderManager
:::
```c=
// binder.c
static int binder_ioctl_set_ctx_mgr(struct file *filp,
struct flat_binder_object *fbo)
{
int ret = 0; // 0 為成功
// 從 Binder 文件取回進程資料
struct binder_proc *proc = filp->private_data;
struct binder_context *context = proc->context;
struct binder_node *new_node;
kuid_t curr_euid = current_euid();
// 互斥鎖
mutex_lock(&context->context_mgr_node_lock);
if (context->binder_context_mgr_node) {
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
ret = -EBUSY;
goto out;
}
// 將當前進程 (service manager) 設定為
ret = security_binder_set_context_mgr(proc->cred);
if (ret < 0)
goto out;
// 判斷 service manager uid
if (uid_valid(context->binder_context_mgr_uid)) {
// curr_euid 是當前進程的 uid
if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) {
... 省略錯誤訊息
ret = -EPERM;
goto out;
}
} else {
// 將 servicemanager uid 設定為當前 uid
context->binder_context_mgr_uid = curr_euid;
}
// 創建一個 binder 節點 (fbo 是 flat_binder_object)
// @ 追蹤 binder_new_node 方法
new_node = binder_new_node(proc, fbo);
if (!new_node) {
ret = -ENOMEM;
goto out;
}
// 安全鎖
binder_node_lock(new_node);
// 增加本地強弱計數、指針引用
new_node->local_weak_refs++;
new_node->local_strong_refs++;
new_node->has_strong_ref = 1;
new_node->has_weak_ref = 1;
// 將新節點設定為 binder manager
context->binder_context_mgr_node = new_node;
binder_node_unlock(new_node);
binder_put_node(new_node);
out:
// 解除互斥鎖
mutex_unlock(&context->context_mgr_node_lock);
return ret;
}
```
6. `binder_new_node` 函數:在 Kernal space 開闢一個新的 `binder_node` 區塊,並將 `flat_binder_object` 加入到 proc 的紅黑樹上
:::success
* 首先檢查 (透過 ptr,也就是 BBinder 的若參考計數當地址) 當前 proc 內是否有相對應的 binder_node,沒有的話則創建
:::
```c=
// binder.c
static struct binder_node *binder_new_node(struct binder_proc *proc,
struct flat_binder_object *fp)
{
// 創建一個 binder_node 空間
struct binder_node *node;
struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!new_node)
return NULL;
binder_inner_proc_lock(proc);
// @ 追蹤 binder_init_node_ilocked 函數
node = binder_init_node_ilocked(proc, new_node, fp);
binder_inner_proc_unlock(proc);
if (node != new_node)
/*
* binder_node 已經被其他 thread 添加
*/
kfree(new_node);
return node;
}
static struct binder_node *binder_init_node_ilocked(
struct binder_proc *proc,
struct binder_node *new_node,
struct flat_binder_object *fp)
{
struct rb_node **p = &proc->nodes.rb_node;
struct rb_node *parent = NULL;
struct binder_node *node;
binder_uintptr_t ptr = fp ? fp->binder : 0;
binder_uintptr_t cookie = fp ? fp->cookie : 0;
__u32 flags = fp ? fp->flags : 0;
s8 priority;
assert_spin_locked(&proc->inner_lock);
// 找到紅黑樹可以插入的點
while (*p) {
parent = *p;
node = rb_entry(parent, struct binder_node, rb_node);
if (ptr < node->ptr)
p = &(*p)->rb_left;
else if (ptr > node->ptr)
p = &(*p)->rb_right;
else {
/*
* A matching node is already in
* the rb tree. Abandon the init
* and return it.
*/
binder_inc_node_tmpref_ilocked(node);
return node;
}
}
node = new_node;
binder_stats_created(BINDER_STAT_NODE);
node->tmp_refs++;
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
... 省略部份
return node;
}
```
## [ServiceManager](https://android.googlesource.com/platform/frameworks/native/+/master/cmds/servicemanager/main.cpp) 進入循環 - [Looper](https://android.googlesource.com/platform/system/core/+/master/libutils/Looper.cpp)
* 在上面已經分析 Binder 的啟動(open)、開啟 Binder 對應用進程的映射(mmap)、並對 Binder 傳送命令將 ServiceManager 設定為 Binder 管理者(ioctl)
現在是進入 Loop 循環等待使用者的請求
```cpp=
// /servicemanager/main.cpp
int main(int argc, char** argv) {
... 省略部份
// 1-1. 啟動 Looper
sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
// 1-2. 設定 callback
BinderCallback::setupTo(looper); // 會透過 IPCThreadState 進入 Binder 循環
ClientCallbackCallback::setupTo(looper, manager);
// Looper 進入循環監聽
while(true) {
// 2. 讀取 Binder 驅動
looper->pollAll(-1);
}
return EXIT_FAILURE;
}
```
### [**Looper**](https://cs.android.com/android/platform/superproject/+/master:system/core/libutils/Looper.cpp) 啟動循環 - 設定 Callback
1. 使用 [**Looper**](https://android.googlesource.com/platform/system/core/+/master/libutils/Looper.cpp)#prepare 函數創建 Looper 對象
```cpp=
// Looper.cpp
sp<Looper> Looper::prepare(int opts) {
bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
sp<Looper> looper = Looper::getForThread();
if (looper == nullptr) {
// 目前 allowNonCallbacks 是 false
looper = new Looper(allowNonCallbacks);
Looper::setForThread(looper);
}
... log 訊息
return looper;
}
```
2. 設定 Looper 的 Callback
* `setupTo` 函數:設定 Looper 的 fd,讓 Looper 拉取指定檔案 FD 的訊息 (目前就是 `/dev/binder`)
* `handleEvent` 函數:未來接收到 Looper 訊息時,由 BinderCallback 接手處理
```cpp=
// /cmds/servicemanager/main.cpp
class BinderCallback : public LooperCallback {
public:
static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
sp<BinderCallback> cb = sp<BinderCallback>::make();
int binder_fd = -1;
// 將 binder_fd 丟入
// @ 之後分析 setupPolling
IPCThreadState::self()->setupPolling(&binder_fd);
... log 訊息
// 讓該 looper 對指定的 FD 觀察
int ret = looper->addFd(binder_fd,
Looper::POLL_CALLBACK,
Looper::EVENT_INPUT,
cb,
nullptr /*data*/);
... log 訊息
return cb;
}
int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
// 由 IPCThreadState#handlePolledCommands 接手處理 BinderClient 傳入的命令
IPCThreadState::self()->handlePolledCommands();
return 1; // 繼續接收
}
};
```
### [IPCThreadState](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/IPCThreadState.cpp) - 設定 Thread 為 BinderThread
:::info
目前主要處理的命令是 `ENTER_LOOPER`
:::
* Looper 在準備時,會呼叫 [**IPCThreadState**](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/IPCThreadState.cpp)#setupPolling 方法,並在這裡會對 Binder 傳送 `BC_ENTER_LOOPER` 命令,而 Binder 傳送命令就必須由 ioctl 函數開始
> `BC_ENTER_LOOPER` 命令會將當前 Thread 註冊為 BinderThread
```cpp=
// IPCThreadState.cpp
status_t IPCThreadState::setupPolling(int* fd)
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
// 對 BinderDriver 寫入 BC_ENTER_LOOPER 命令
mOut.writeInt32(BC_ENTER_LOOPER);
// @ 查看 flushCommands
flushCommands();
// 改變 fd 數值 (/dev/binder)
// fd 為 ServiceManager 映射 (/dev/binder) 在自身進程上的描述偏移
*fd = mProcess->mDriverFD;
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mCurrentThreads++;
pthread_mutex_unlock(&mProcess->mThreadCountLock);
return 0;
}
void IPCThreadState::flushCommands()
{
if (mProcess->mDriverFD < 0)
return;
// @ 追蹤 talkWithDriver 方法
talkWithDriver(false);
if (mOut.dataSize() > 0) {
talkWithDriver(false);
}
if (mOut.dataSize() > 0) {
ALOGW("mOut.dataSize() > 0 after flushCommands()");
}
}
```
> 
* **IPCThreadState# talkWithDriver 函數**:準備要與 Binder 通訊的資料,在透過 User space 的 `ioctl` 函數呼叫到 Kernel Space 的 `binder_ioctl` 函數
```cpp=
// IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive) // doReceive = true
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
binder_write_read bwr
// 判斷 mIn#position 位置 是否有移動
// 有移動並大於 dataSize 代表有資料
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// 在讀取 mIn 時我們不想寫入任何 mOut 資料
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data(); // 寫入資料
// 目前狀況是 doReceive = true
// 並且 needRead = true (有資料要讀取)
if (doReceive && needRead) {
// 要讀取的資料
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
... log 訊息
// 如果沒有任何事情要做(不須 read | write)則即時返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
// consumed 設定為 0
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
... log 訊息
#if defined(__ANDROID__)
// 呼叫 Kernel#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;
}
... log 訊息
} while (err == -EINTR);
... 省略 err 錯誤處理
return err;
}
```
* 到這個步驟(binder_ioctl)後就進入了 Kernel space (BinderDriver) 空間
1. 如果沒有新的請求,就會讓當前進入 Binder 的 Thread 休眠
```cpp=
// binder.c
static long binder_ioctl(struct file *filp,
unsigned int cmd, // BINDER_WRITE_READ
unsigned long arg)
{
int ret;
// 從 Binder 文件中取出 proc 訊息
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
... 省略部份
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
}
```
2. 取得進入 Kernel space 的 proc thread,並處理 `BINDER_WRITE_READ` 命令
```cpp=
// binder.c
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
// 從 Binder 文件中取出 proc 訊息
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
... 省略部份
// 取得進入 Kernel space 的 proc thread (目前來講就是 ServiceManager 的 MainThread)
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
goto err;
};
switch (cmd) {
case BINDER_WRITE_READ:
// @ binder_ioctl_write_read
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
... 省略其他 case
}
... 省略錯誤處理
return ret;
}
```
3. **binder_ioctl_write_read 函數**:首先先將使用者空間數據進行拷貝 (`copy_from_user`),再針對 read/write 呼叫不同函數處理
| 行為 | 處理函數 |
| -------- | -------- |
| read | binder_thread_read |
| write | binder_thread_write |
```cpp=
// binder.c
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;
unsigned int size = _IOC_SIZE(cmd);
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) {
// @ 分析 binder_thread_write
ret = binder_thread_write(proc, thread,
bwr.write_buffer, // 目前內部指令是 BC_ENTER_LOOPER
bwr.write_size,
&bwr.write_consumed);
... 省略錯誤處理
}
// 由於當前要處理 `BC_ENTER_LOOPER` 並沒有 read
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
... 省略錯誤處理
}
... debug 訊息
// 將內核空間數據 (bwr) 複製到使用者空間(ubuf)
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
```
4. **binder_thread_write 函數**:處理 `BC_ENTER_LOOPER` 命令,最終會把 ServiceManager 用來跟 Binder 通訊的 **thread 設置狀態為 `BINDER_LOOPER_STATE_ENTERED`**
```c=
// binder.cpp
static int binder_thread_write(
struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, // bwr.write_buffer
size_t size, // bwr.write_size
binder_size_t *consumed) // bwr.write_consumed
{
uint32_t cmd;
// buffer = cmd + 對應數據
// 取得調用者的 buffer address
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
// 1. 設定開頭、結尾的指針
void __user *ptr = buffer + *consumed; // 跳過已處理過得部份,取得開始部份
void __user *end = buffer + size; // 指向 buffer 結尾
while (ptr < end && thread->return_error == BR_OK) {
// 2. 獲取 cmd
// 當前 cmd 是 `BC_ENTER_LOOPER`
if (get_user_preempt_disabled(cmd, (uint32_t __user *)ptr))
return -EFAULT;
// 取出指令後移動指針,讓指針移動到數據開頭
ptr += sizeof(uint32_t);
// 3. 統計數據
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)]++;
}
// 判斷 cmd
switch (cmd) {
... 省略部份 case
case BC_ENTER_LOOPER:
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
// 已註冊
... 錯誤處理
}
// 為該 Binder_thread 設定 flag
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
}
}
}
```
> 
### Looper 循環
* Binder 準備好後,Loop 就準備進入 while 循環,持續拉取資料處理,再有資料時調用 Callback (BinderCallback 類),詳細請看註解說明
```cpp=
// Looper.h
// 宣告
int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
// 使用內聯 pollAll
inline int pollAll(int timeoutMillis) {
// @ 查看 pollAll
return pollAll(timeoutMillis, nullptr, nullptr, nullptr);
}
// --------------------------------------------------
// Looper.cpp
// 目前 timeoutMillis 傳入是 -1
int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
if (timeoutMillis <= 0) {
int result;
do {
// @ 查看 pollOnce
result = pollOnce(timeoutMillis, outFd, outEvents, outData);
} while (result == POLL_CALLBACK);
return result;
} else {
... 省略
}
}
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
int result = 0;
for (;;) {
... 省略部份
// @ 查看 pollInner 函數
result = pollInner(timeoutMillis);
}
}
int Looper::pollInner(int timeoutMillis) {
... 省略部份
// Poll.
int result = POLL_WAKE;
mResponses.clear();
mResponseIndex = 0;
// We are about to idle.
mPolling = true;
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd.get(),
eventItems,
EPOLL_MAX_EVENTS,
timeoutMillis); // -1
// No longer idling.
mPolling = false;
// Acquire lock.
mLock.lock();
// Rebuild epoll set if needed.
if (mEpollRebuildRequired) {
mEpollRebuildRequired = false;
rebuildEpollLocked();
goto Done;
}
// Check for poll error.
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
ALOGW("Poll failed with an unexpected error: %s", strerror(errno));
result = POLL_ERROR;
goto Done;
}
// Check for poll timeout.
if (eventCount == 0) { // 沒有任何事件
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - timeout", this);
#endif
result = POLL_TIMEOUT;
goto Done;
}
// 處理事件
for (int i = 0; i < eventCount; i++) {
const SequenceNumber seq = eventItems[i].data.u64;
uint32_t epollEvents = eventItems[i].events;
if (seq == WAKE_EVENT_FD_SEQ) {
... 省略 // 喚醒指定檔案並進行觀察
} else {
const auto& request_it = mRequests.find(seq);
if (request_it != mRequests.end()) {
const auto& request = request_it->second;
int events = 0;
if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
// 添加要通知的事件到列表
mResponses.push({.seq = seq, .events = events, .request = request});
} else {
... log 訊息
}
}
}
Done: ;
... 省略部份
// 調用 callback
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
if (response.request.ident == POLL_CALLBACK) { // 該事件需要 CallBack
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
// 呼叫 callback
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
AutoMutex _l(mLock);
removeSequenceNumberLocked(response.seq);
}
// Clear the callback reference in the response structure promptly because we
// will not clear the response vector itself until the next poll.
response.request.callback.clear();
result = POLL_CALLBACK;
}
}
return result;
}
```
> 
### Looper 接收訊息 - BinderCallBack
* 在上面我們有分析過 ServiceManager 的 Looper 啟動、循環,它監聽 Binder 文件的改動,並自己透過 **BinderCallback#==handleEvent==** 處理 Binder 接收到的 command
```cpp=
// /servicemanager/main.cpp
class BinderCallback : public LooperCallback {
public:
... 省略部份
int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
// @ 由 IPCThreadState#handlePolledCommands 接手處理 Binder 命令
IPCThreadState::self()->handlePolledCommands();
return 1; // 繼續接收
}
};
int main(int argc, char** argv) {
... 省略部份
// 創建 ServiceManager 實例
sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
LOG(ERROR) << "Could not self register servicemanager";
}
// 設定 ServiceManager 處理 Binder 訊息
IPCThreadState::self()->setTheContextObject(manager);
// @ becomeContextManager 將當前進程設定為 Binder 管理者
ps->becomeContextManager();
// 啟動 Looper
sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
BinderCallback::setupTo(looper);
ClientCallbackCallback::setupTo(looper, manager);
// Looper 進入循環監聽
while(true) {
looper->pollAll(-1);
}
return EXIT_FAILURE;
}
```
* [**IPCThreadState**](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/IPCThreadState.cpp;l=1;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=IPCThreadState.cpp&ss=android%2Fplatform%2Fsuperproject)#handlePolledCommands 方法:接手處理 Binder 所收到的命令
```cpp=
// IPCThreadState.cpp
status_t IPCThreadState::handlePolledCommands()
{
status_t result;
do {
// @ 追蹤 getAndExecuteCommand
result = getAndExecuteCommand();
} while (mIn.dataPosition() < mIn.dataSize());
processPendingDerefs();
flushCommands();
return result;
}
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver(); // 去 kernel space (BinderDriver) 取得指令
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
... 省略部份
// @ 追蹤 executeCommand
result = executeCommand(cmd);
... 省略部份
}
...
return result;
}
sp<BHwBinder> the_context_object;
// ServiceManager 有指定由自身處理
void IPCThreadState::setTheContextObject(sp<BHwBinder> obj)
{
the_context_object = obj;
}
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BHwBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
... 省略其他 case
// 收到 BinderDriver 訊息,要求 ServiceManager 交易
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
binder_transaction_data_secctx tr_secctx;
binder_transaction_data& tr = tr_secctx.transaction_data;
... 省略
const pid_t origPid = mCallingPid;
const char* origSid = mCallingSid;
const uid_t origUid = mCallingUid;
const int32_t origStrictModePolicy = mStrictModePolicy;
const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
... 省略
Parcel reply;
status_t error;
bool reply_sent = false;
... 省略
// 訪問物件是 ServiceManager 時,ptr 設定為 0
if (tr.target.ptr) {
// 有指定目標
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) { // 嘗試增加目標的強引用計數
error = reinterpret_cast<BHwBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags, reply_callback);
reinterpret_cast<BHwBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
// 沒有指定目標 (目前狀況)
// @ 分析 transact 函數
error = the_context_object
->transact(tr.code,
buffer,
&reply,
tr.flags,
reply_callback);
}
... 省略
}
break;
}
}
```
* [**Binder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/Binder.cpp)#`transact` 函數:這裡就可以看到 Service 主要在負責的 `onTransact` 函數
```java=
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
if (reply != nullptr && (flags & FLAG_CLEAR_BUF)) {
reply->markSensitive();
}
status_t err = NO_ERROR;
switch (code) {
... 省略部分 case
default:
// @ 查看 onTransact
err = onTransact(code, data, reply, flags);
break;
}
...
return err;
}
```
### ServiceManager 重寫 transact - addService
* IPCThreadState#`transact` 函數:
1. 如果是作為 Server 方 (像是 ServiceManager),在 `transact` 函數時,就會去 **重寫 `onTransact` 函數**
2. 真正的命令則是在 重寫 `onTransact` 函數 處理
* ServiceManager 在 [**BnServiceManager**](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/native/libs/binder/libbinder_aidl_test_stub-cpp-source/gen/android/os/IServiceManager.cpp) 中複寫 `onTransact` 函數,這裡關注 `addService` 這個命令,在接收到這個命令後,會去讀取 BinderDriver 傳入的 服務名稱、IBinder ...
最後會呼叫 [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp)#`addService` 函數
```c=
// BnServiceManager.cpp
::android::status_t BnServiceManager::onTransact(uint32_t _aidl_code,
const ::android::Parcel& _aidl_data,
::android::Parcel* _aidl_reply,
uint32_t _aidl_flags) {
::android::status_t _aidl_ret_status = ::android::OK;
switch (_aidl_code) {
... 省略其他 case
case BnServiceManager::TRANSACTION_addService:
{
::std::string in_name;
::android::sp<::android::IBinder> in_service;
bool in_allowIsolated;
int32_t in_dumpPriority;
_aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
...
// @ 有空可以看一下 readStrongBinder 函數
_aidl_ret_status = _aidl_data.readStrongBinder(&in_service);
... 省略讀取 Parcel 資料
// 呼叫 addService 方法
::android::binder::Status _aidl_status(
// @ 追蹤 addService
addService(in_name,
in_service,
in_allowIsolated,
in_dumpPriority)
);
// 回覆 BinderDriver
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
if (!_aidl_status.isOk()) {
break;
}
}
}
```
:::success
* [**Parcel**](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/Parcel.cpp)#`readStrongBinder` 函數:創建本地 Proxy,並讀取 BinderDriver 的數據,並 **透過 Parcel#`readObject` 來讀取 BinderServer**
```cpp=
// Parcel.cpp
status_t Parcel::readStrongBinder(sp<IBinder>* val) const
{
// @ 查看 readNullableStrongBinder
status_t status = readNullableStrongBinder(val);
...
return status;
}
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
// @ 查看 unflatten_binder
return unflatten_binder(ProcessState::self(), *this, val);
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject<flat_binder_object>();
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(nullptr, *flat, in);
// 使用者註冊 Service 時,傳入會進這個 casee
case BINDER_TYPE_HANDLE:
// 創建一個本地代理,對應到 Binder ref
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpHwBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
```
:::
* [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp)#`addService` 函數:將 Service 存到 Map (`mNameToService`) 中
> Key:**使用者設定的 Name**
>
> Value:**ServiceManager 的代理對象**;方便之後在 BinderDriver 找到對應的 binder_ref
```cpp=
// ServiceManager.h
class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
public:
...
private
struct Service {
sp<IBinder> binder; // not null
bool allowIsolated;
int32_t dumpPriority;
bool hasClients = false; // notifications sent on true -> false.
bool guaranteeClient = false; // forces the client check to true
Access::CallingContext ctx; // process that originally registers this
// the number of clients of the service, including servicemanager itself
ssize_t getNodeStrongRefCount();
};
...
using ServiceMap = std::map<std::string, Service>;
ServiceMap mNameToService;
}
// -----------------------------------------------------------------
// ServiceManager.cpp
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
auto ctx = mAccess->getCallingContext();
... 省略部分
// implicitly unlinked when the binder is removed
if (binder->remoteBinder() != nullptr &&
binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
ALOGE("Could not linkToDeath when adding %s", name.c_str());
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");
}
auto it = mNameToService.find(name);
... 省略檢查
// 覆蓋舊的同名 Service
mNameToService[name] = Service{
.binder = binder,
.allowIsolated = allowIsolated,
.dumpPriority = dumpPriority,
.ctx = ctx,
};
...
return Status::ok();
}
```
:::info
* 這邊我們可以看出 Service Name 的重要性,**Service Name 必須是唯一值**
:::
## IMediaDeathNotifier - getService 系統服務
這裡以客戶端 [**IMediaDeathNotifier**](https://android.googlesource.com/platform/frameworks/av/+/master/media/libmedia/IMediaDeathNotifier.cpp) 要取得 MediaPlayerService 為例(兩者不同進程),客戶端要透過 ServiceManager 取得 `"media.player"` 服務
```cpp=
// IMediaDeathNotifier.cpp
sp<IMediaPlayerService> IMediaDeathNotifier::sMediaPlayerService;
const sp<IMediaPlayerService>
IMediaDeathNotifier::getMediaPlayerService()
{
ALOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
// 產生 BpServiceManager
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
// 透過代理 BpServiceManager 與 ServiceManager 通訊
// @ 追蹤 getService 函數
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
ALOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
// 監聽 binder 死亡
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
// 透過 interface_cast 取得 IMediaPlayerService 的代理
// 最終會轉換成 ++BpMediaPlayerService++
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
}
```
:::info
* **`interface_cast` 宏 ?**
可以產生 `BpMediaPlayerService`,而其內部包裝的就是 BpBinder,而 BpBinder 的建構函數就需要傳入一個 handle (服務描述)
所以其原理都是透過 BpBinder 的 **handle 來找到對應服務**,由此我們可以知道 **`sm->getService` 是在 ServiceManager 中 ==找尋 handle !!==**
> (handle 也稱為控制碼)
>
> eg. ServiceManager's handle 固定為 0
:::
> 
### [IServiceManager.cpp](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_vendor.UpsideDownCake_x86_64_silvermont_shared/gen/aidl/android/os/IServiceManager.cpp) - getService 取得 BpBinder
:::info
新版沒有 [**BpServiceManager**](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_vendor.UpsideDownCake_x86_64_silvermont_shared/gen/aidl/android/os/IServiceManager.cpp) 實做(新版改為 aidl 自動產生 code)
:::
```java=
// IServiceManager.cpp
// ServiceManager 介面名
namespace os {
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager")
}
::android::binder::Status BpServiceManager::getService(
const ::std::string& name,
::android::sp<::android::IBinder>* _aidl_return) {
::android::Parcel _aidl_data;
_aidl_data.markForBinder(remoteStrong());
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
...
// ServiceManager 的介面名稱
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
...
// 要搜尋的 Service 的介面名稱
_aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
...
// 查看
_aidl_ret_status = remote()->transact(
BnServiceManager::TRANSACTION_getService, // 給 ServiceManager 的命令
_aidl_data,
&_aidl_reply,
0);
...
_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
...
// 讀取 ServiceMananger 回覆,也就是讀取 Binder Service 的 ref 引用
_aidl_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return);
...
return _aidl_status;
}
```
:::success
* [**Parcel**](https://cs.android.com/android/platform/superproject/+/master:system/libhwbinder/Parcel.cpp)#`readNullableStrongBinder` 函數:讀取 Binder 物件
```cpp=
// Parcel.cpp
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
// @ 查看 unflatten_binder
return unflatten_binder(ProcessState::self(), *this, val);
}
// 這個函數上面有說明
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject<flat_binder_object>();
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(nullptr, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpHwBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
```
:::
* 這裡取得的 remote() 函數取得的就是 [**BpBinder 對象**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/BpBinder.cpp),所以其實它是在呼叫 BpBinder#**transact** (內部存有控制碼 handle) 方法
:::info
這邊呼叫 IPCThreadState#transact 傳入的 Handle 控制碼是 0
:::
```cpp=
// BpBinder.cpp
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;
if (CC_UNLIKELY(isRpcBinder())) {
// Rpc Binder...
} else {
// @ IPCThreadState#transact 分析
status = IPCThreadState::selTextf()->transact(
binderHandle(), // 0 (ServiceManager)
code, // CHECK_SERVICE_TRANSACTION
data,
reply,
flags
);
}
... 省略部份
// Server 已死亡
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
```
> 
### [IPCThreadState](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/IPCThreadState.cpp) - transact 傳送
:::info
這裡我們是作為客戶端在使用 `transact` 函數,向 BindeDriver 發送資料
:::
* 在了解 IPCThreadState 後 ([**IPCThreadState 介紹**](https://hackmd.io/_8ne10VrSK-mK6nlyxL5RQ?view#IPCThreadState---TLS)),我們接著來看 BpServiceManager#`addService` 函數所使用到的 `transact` 方法,這裡有幾個重要函數
| 函數名 | 功能 |
| -------- | -------- |
| writeTransactionData | 傳輸數據到 BinderDriver (kernel) |
| waitForResponse | 等待 BinderDriver (kernel) 回覆 |
:::success
* BinderDriver 指令取名方式
傳向 BinderDriver 的指令是有規則的,`BC_` 開頭的是向 BinderDriver 發送,而 `BR_` 則是 BinderDriver 回覆使用者
:::
```cpp=
// IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle, // 0
uint32_t code, // ADD_SERVICE_TRANSACTION
const Parcel& data,
Parcel* reply, uint32_t flags)
{
... log 訊息
status_t err;
flags |= TF_ACCEPT_FDS;
... log 訊息
// @ writeTransactionData 函數
// 傳遞 cmd 為 BC_TRANSACTION
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
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(nullptr, nullptr);
}
return err;
}
```
1. **writeTransactionData 函數**:首先會準備要傳向 BinderDriver (kernel) 的數據結構 `(binder_transaction_data)` 結構,對該結構填充數據
| binder_transaction_data 成員 | 功能 | 當前數據 |
| -------- | -------- | - |
| cmd | BinderDriver (kernel) 需要處理的指令 | `BC_TRANSACTION` |
| handle | 標示要傳遞的目標 | `0` (ServiceManager) |
| code | 接收進程會收到的命令 | 傳遞給 ServiceManager 命令 `CHECK_SERVICE_TRANSACTION` |
```cpp=
// IPCThreadState.cpp
// 傳遞 cmd 為 BC_TRANSACTION
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.ptr = 0;
tr.target.handle = handle; // 目前是 0
tr.code = code; // 目前是 CHECK_SERVICE_TRANSACTION
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck(); // 檢查 Parcel 資料結構是否有錯誤
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_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 = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = 0;
tr.data.ptr.offsets = 0;
} else {
return (mLastError = err);
}
// 將給 BinderKernel 的命令寫入 mOut 中
mOut.writeInt32(cmd); // 目前是 BC_TRANSACTION
// 將數據包寫入 mOut 中
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
```
2. **waitForResponse 函數**:主要是與 Binder kernel 通訊,並處理 BinderDriver 的回覆(處理以 `BR_` 開頭的命令),其中有兩個較重要的函數
| 函數名 | 功能 |
| - | - |
| talkWithDriver | 對 BinderDriver (kernel) 寫入(mOut) or 讀取(mIn) |
| executeCommand | 處理從 Binder kernel 回傳的命令 |
```cpp=
// IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
// 與 Binder 通訊
// @ 分析 talkWithDriver 函數
if ((err=talkWithDriver()) < NO_ERROR) break;
// 到這裡就代表 Binder kernel 有回覆 (mIn 有資料)
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
... log 訊息
// 有許多 BR_ 開頭的 command,這裡只留下幾個
switch (cmd) {
...
case BR_TRANSACTION_COMPLETE: // BinderDriver 回覆使用者,傳輸完成
if (!reply && !acquireResult) goto finish;
break;
... 其他 case
default:
// 處理各種命令
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
...
return err;
}
status_t IPCThreadState::talkWithDriver(bool doReceive) // 預設 doReceive = true
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
binder_write_read bwr
// 判斷 mIn#position 位置 是否有移動
// 有移動並大於 dataSize 代表有資料
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// 在讀取 mIn 時我們不想寫入任何 mOut 資料
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data(); // 寫入資料
// 目前狀況是 doReceive = true
// 並且 needRead = true (有資料要讀取)
if (doReceive && needRead) {
// 要讀取的資料
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
... log 訊息
// 如果沒有任何事情要做(不須 read | write)則即時返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
// consumed 設定為 0
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
... log 訊息
#if defined(__ANDROID__)
// 呼叫 Kernel#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;
}
... log 訊息
} while (err == -EINTR);
... 省略 err 錯誤處理
return err;
}
```
> 
* 客戶端的 IPCThreadState#writeTransactionData 向 Binder 發送 `BC_TRANSACTION` 命令後,Binder 驅動會將命令轉為 `BR_TRANSACTION`,併發送給 ServiceManager
> 
### [ServiceManager](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_vendor.UpsideDownCake_x86_64_silvermont_shared/gen/aidl/android/os/IServiceManager.cpp) - onTransact 接收命令
:::info
ServiceManager 繼承 BBinder,並透過 AIDL 複寫 `onTransact` 函數
:::
* 首先我們要先知道 [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.h;l=19;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=ServiceManager.h&sq=&ss=android%2Fplatform%2Fsuperproject) **繼承於 BBinder 類**,IPCThreadState#`executeCommand` 才可以呼叫 `transact` 的方法
1. ServiceManager:繼承 BnServiceManager
2. BnServiceManager:繼承 BnInterface<IServiceManager\>,[**BnInterface**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/IInterface.h;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f;l=84) 是一個模板類,而 [**BnServiceManager**](https://cs.android.com/android/platform/superproject/+/master:prebuilts/vndk/v32/x86/include/generated-headers/frameworks/native/libs/binder/libbinder/android_vendor.32_x86_shared/gen/aidl/android/os/BnServiceManager.h;l=10;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=BnServiceManager&ss=android%2Fplatform%2Fsuperproject) 由 aidl 自動產生,並實作 `onTransact` 方法
3. BnInterface:繼承於 [**BBinder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/Binder.h;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f;l=30),實作 `transact` 方法,**處理完後將實際業務邏輯交給 ServiceManager#onTransact 方法**
> 
```cpp=
// ServiceManager.h
class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
...
}
// --------------------------------------------------------------
// BnServiceManager.h
class BnServiceManager : public ::android::BnInterface<IServiceManager> {
public:
static constexpr uint32_t TRANSACTION_getService = ::android::IBinder::FIRST_CALL_TRANSACTION + 0;
static constexpr uint32_t TRANSACTION_checkService = ::android::IBinder::FIRST_CALL_TRANSACTION + 1;
static constexpr uint32_t TRANSACTION_addService = ::android::IBinder::FIRST_CALL_TRANSACTION + 2;
static constexpr uint32_t TRANSACTION_listServices = ::android::IBinder::FIRST_CALL_TRANSACTION + 3;
static constexpr uint32_t TRANSACTION_registerForNotifications = ::android::IBinder::FIRST_CALL_TRANSACTION + 4;
static constexpr uint32_t TRANSACTION_unregisterForNotifications = ::android::IBinder::FIRST_CALL_TRANSACTION + 5;
static constexpr uint32_t TRANSACTION_isDeclared = ::android::IBinder::FIRST_CALL_TRANSACTION + 6;
static constexpr uint32_t TRANSACTION_getDeclaredInstances = ::android::IBinder::FIRST_CALL_TRANSACTION + 7;
static constexpr uint32_t TRANSACTION_updatableViaApex = ::android::IBinder::FIRST_CALL_TRANSACTION + 8;
static constexpr uint32_t TRANSACTION_registerClientCallback = ::android::IBinder::FIRST_CALL_TRANSACTION + 9;
static constexpr uint32_t TRANSACTION_tryUnregisterService = ::android::IBinder::FIRST_CALL_TRANSACTION + 10;
static constexpr uint32_t TRANSACTION_getServiceDebugInfo = ::android::IBinder::FIRST_CALL_TRANSACTION + 11;
explicit BnServiceManager();
// BnServiceManager.cpp 會實作
::android::status_t onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) override;
}
// --------------------------------------------------------------
// IInterface.h
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
};
// --------------------------------------------------------------
// Binder.h
class BBinder : public IBinder
{
public:
...
protected:
// 繼承該類必須 override 該方法
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
```
* BnServiceManager#`onTransact` 函數:取出使用者傳入的 ServiceName 開始搜尋
```cpp=
::android::status_t BnServiceManager::onTransact(uint32_t _aidl_code,
const ::android::Parcel& _aidl_data,
::android::Parcel* _aidl_reply,
uint32_t _aidl_flags) {
::android::status_t _aidl_ret_status = ::android::OK;
switch (_aidl_code) {
case BnServiceManager::TRANSACTION_getService:
{
::std::string in_name;
::android::sp<::android::IBinder> _aidl_return;
...
// 使用者搜尋的 Service Name
_aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
...
::android::binder::Status _aidl_status(
// @ 查看 getService 函數
getService(in_name, &_aidl_return)
);
// 將搜尋結果寫入 Parcel
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
... 省略檢查
// 增加強計數
_aidl_ret_status = _aidl_reply->writeStrongBinder(_aidl_return);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
}
return _aidl_ret_status;
}
}
```
* [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp)#`getService` 函數:透過 ServiceName 查詢 ServiceManager 中的列表,並找到對應的 IBinder 返回
```cpp=
// ServiceManager.cpp
Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) {
// @ 查看 tryGetService
*outBinder = tryGetService(name, true);
return Status::ok();
}
sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
auto ctx = mAccess->getCallingContext();
sp<IBinder> out;
Service* service = nullptr;
if (auto it = mNameToService.find(name); it != mNameToService.end()) {
service = &(it->second);
... 省略部分
// 找到目標 Service
out = service->binder;
}
...
if (!out && startIfNotFound) {
// 啟動服務
tryStartService(name);
}
...
return out;
}
```
## ServiceManager 方法
### 檢查服務 - checkService
* Client 端會透過 Proxy 傳遞 `CHECK_SERVICE_TRANSACTION` 命令到 ServiceManager 中
> 
* 由於實現 onTransact 方法的 BnServiceManager 類是由 aidl 自動產生,所以這裡我們跳過,只需要知道目前的 `CHECK_SERVICE_TRANSACTION` 命令會對應到 [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp;l=1;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=ServiceManager.cpp&sq=&ss=android%2Fplatform%2Fsuperproject)#`checkService` 方法
> 其實 CHECK_SERVICE_TRANSACTION 會對應 TRANSACTION_checkService
```cpp=
// ServiceManager.cpp
// 傳入的 name 是 "media.player"
Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
*outBinder = tryGetService(name, false);
// returns ok regardless of result for legacy reasons
return Status::ok();
}
// 傳入的 name 是 "media.player"
sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
auto ctx = mAccess->getCallingContext();
sp<IBinder> out;
Service* service = nullptr;
// 透過 name 尋找 service
if (auto it = mNameToService.find(name); it != mNameToService.end()) {
service = &(it->second);
if (!service->allowIsolated) {
uid_t appid = multiuser_get_app_id(ctx.uid);
bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;
if (isIsolated) {
return nullptr;
}
}
out = service->binder;
}
if (!mAccess->canFind(ctx, name)) {
return nullptr;
}
if (!out && startIfNotFound) {
tryStartService(name);
}
...
return out;
}
```
從上面可以看到 ServiceManager 會 **透過 `mNameToService.find(name)` 來找到對應的 Service 結構**,而該結構內就會有 目標 IBinder
```cpp=
// ServiceManager.h
class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
...
private:
struct Service {
sp<IBinder> binder; // not null
bool allowIsolated;
int32_t dumpPriority;
bool hasClients = false; // notifications sent on true -> false.
bool guaranteeClient = false; // forces the client check to true
pid_t debugPid = 0; // the process in which this service runs
// the number of clients of the service, including servicemanager itself
ssize_t getNodeStrongRefCount();
};
using ServiceMap = std::map<std::string, Service>;
ServiceMap mNameToService;
}
```
:::info
* 從這裡可以知道,ServiceManager 有一個 Map,透過 name 作為 key 找到目標 IBinder
這個 IBinder 可能是本地(BBinder)、代理(BpBinder)
:::
### 添加服務 - addService
* Native 端註冊流程請參考 [**Binder - Native Binder 原理篇**](https://hackmd.io/_8ne10VrSK-mK6nlyxL5RQ?view#Client-%E5%90%91-ServiceManager-%E8%A8%BB%E5%86%8A)
> 
* 由於實現 onTransact 方法的 BnServiceManager 類是由 aidl 自動產生,所以這裡我們跳過,只需要知道目前的 `ADD_SERVICE_TRANSACTION` 命令會對應到 [**ServiceManager**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/servicemanager/ServiceManager.cpp;l=1;drc=1b1e0e28fff9b2add0176e5595dfb3497769204f?q=ServiceManager.cpp&sq=&ss=android%2Fplatform%2Fsuperproject)#`addService` 方法
> 其實 ADD_SERVICE_TRANSACTION 會對應 addService
```cpp=
// ServiceManager.cpp
// 傳入的 name 是 "media.player"
Status ServiceManager::addService(const std::string& name,
const sp<IBinder>& binder, // BBinder
bool allowIsolated,
int32_t dumpPriority) {
auto ctx = mAccess->getCallingContext();
... 省略部分
// 將 Service 存在 Map 中 (如果存在的話就覆蓋)
mNameToService[name] = Service {
.binder = binder,
.allowIsolated = allowIsolated,
.dumpPriority = dumpPriority,
.debugPid = ctx.debugPid,
};
auto it = mNameToRegistrationCallback.find(name);
if (it != mNameToRegistrationCallback.end()) {
for (const sp<IServiceCallback>& cb : it->second) {
mNameToService[name].guaranteeClient = true;
// 在 registerForNotifications 中檢查權限
cb->onRegistration(name, binder);
}
}
return Status::ok();
}
```
:::success
* IBinder 不是序列化!
Server 在 ServiceManager 註冊完 IBinder 訊息後,Client 取用就必須透過 Kernel space 轉換才能使用
:::
### adb 查看 Service
* 可以透過 adb 查看該裝置所有的 Service
```shell=
adb shell
service list
```
> 
## Appendix & FAQ
:::info
:::
###### tags: `Binder` `Android 系統`