---
title: 'Binder - Native Binder 原理'
disqus: kyleAlien
---
Binder - Native Binder 原理
===
## OverView of Content
Android 的基礎 IPC 機制請看 [**Android IPC 進程通訊**](https://hackmd.io/dJ_kZLhKQqOWawEphX2Vdg?view),這裡就不特別介紹基礎使用
Android IPC 機制的特色是 Binder,而 Binder 系統相當龐大,有分為 Kernel 層、Native 層、Java 層 這三個面向
這裡著重介紹分析 Native 層
[TOC]
## Linux & Binder IPC 通訊原理
基礎的 Linux IPC 通訊機制請參考 [**IPC 通訊機制**](https://hackmd.io/jh6jLfzWQZarUjsQOEQZpw)
### Linux 內核空間
1. 在 Linux 中會將空間分為 ^1.^ User space 使用者空間、^2.^ Kernel space 內核空間,這兩個空間是被隔離的,這樣的好處有
1. 安全性:保護 Kernel space 不讓 User space 隨意訪問
2. 記憶體空間:Kernel space 有專屬的記憶體區塊,其他的空間不可隨意使用
3. 穩定性:即使其他 User space 的應用崩潰也不會影響到 Kernel space 的運作
2. Kernel Space 特色:數據是每個進程共享,但進程與進程之間數據不共享,如下圖 ! (下圖都是在虛擬記憶體中,並非實體記憶體)
> 
3. System call:系統調用是一種 **統稱**,其中有許多的函數都稱為系統調用,**系統調用是用戶空間訪問內核空間的 ++==唯一手段==++**
* 這種行為保證了用戶在訪問內核空間時的一致性,所有的資源由內核親自操控、管理,保證了 **安全性、權限訪問**
:::success
* 函數取名,何為 User?
站在 **Kernel 的角度看,User 就是各個 ++用戶空間++**,之後分析我們會常常看到兩個函數
1. `copy_from_user`:將數據從 User 拷貝到 kenel space
2. `copy_to_user`:將數據從 kenel 拷貝到 User space
:::
> 
### 傳統 Linux IPC 通訊問題
* 傳統 Linux IPC 通訊模型如下
1. 內核空間:**主動** 開闢一塊配存區塊(**內核緩衝**)放置要傳輸的資料
2. 發送數據方:透過 `copy_from_user` 將 User 資料 **複製到內核緩衝區**
3. 接收方:在自己的使用者空間開闢一塊 **使用者緩衝區**
4. 內核空間:透過 `copy_to_user` 將資料 **複製到使用者緩衝區**
> 
* 通過以上的流程可以發現 Linux IPC 機制有以下問題
1. 需要經過 **2 次複製**,資料才可以到達使用者空間(copy_from_user、copy_to_user)
2. **使用者接收數據的緩衝區,無法確定大小**,如果只是進可能將空間擴大,則可能會浪費記憶體空間
### 虛擬記憶體 - 分頁快取 & 內存映射
* 如果對 **虛擬記憶體** 沒有概念的話建議先看看 [**Linux 記憶體管理**](https://hackmd.io/ptxTEwCzQBuxv61dGL_lvA?view#%E8%A8%98%E6%86%B6%E9%AB%94%E7%AE%A1%E7%90%86)、[**分頁快取**](https://hackmd.io/8qOCfHI0SA6cK3l3gDCtOg?view#%E5%88%86%E9%A0%81%E5%BF%AB%E5%8F%96),分頁快取的概念如下圖
> 
* Linux 系統有提供一種機制 **內存映射**:它可以將指定文件(外部文件)的記憶體映射到使用者進程空間,之後操作該內存就會直接反應到記憶體中
* mmap:也就是 Memory Map,它概念是可以 **在核心分頁中分配到的地址**,會直接 **映射到進程的虛擬內存中**
* mmap 的好處是透過 **映射** (想成內核指向文件地址),只需要 **一次性複製**,就可以把資料寫入到文件中(不考慮寫入時機)
> 
* 如果沒有使用內存映射機制,則需要 **兩次複製**,才可以將資料寫入到目標文件中
> 
## Binder 概述
Binder 是基於 OpenBinder 實現(最早是由 PalmInc 公司開發,後來才轉進 Google)
### Binder 通訊原理
* **Binder 是 ++基於分頁快取 & 內存映射++ 來實現**,但這裡的映射並不是真實文件,而是在 dev 區塊的一個內存區塊(想成虛擬文件),簡單來說內核空間會有以下操作
1. 在 Kernel space 開闢一塊,**數據接收區** (**原本由使用者空間提供,++改為核心提供空間++**)
> 
2. 在 Kernel space 開闢一塊,**內存緩衝區** (同內存映射模型)
> 
3. **建立 ++==映射==關係++** (**映射的概念就類似於 Map**),透過**兩次映射**將資料寫到接收進程中,兩次映射如下
* 3-1. 數據接收區 & 內存緩衝區
> 
* 3-2. 內存緩衝區 & 接收進程的虛擬地址
> 
4. 發送資料方,只需要透過 `copy_from_user` 把資料 **複製到內核緩衝區**,之後就可以透過映射,將資料反應到接收方的虛擬記憶體中
> 
### Binder 優點
1. **性能**
傳統 Linux IPC 機制除了共享內存外 (有很多需要注意的部分),大部分都需要兩次複製 (Socket、Pipe、消息對列...)
> 共享內存如下
>
> 
2. **穩定性**
Binder 基於 Client/Server 架構,這種架構通常採用兩層數據結構,而內存共享可能會造成資源的危險,需要使用鎖保護內存 (並可能產生死鎖)
3. **安全性**
* 傳統 IPC 機制需要在用戶層手動指定遠端進程的 ID ( e.g Socket's Port
* 傳統 IPC 機制也無法管理進程的用戶 UID/ 進程 PID,無法判斷遠端進程的安全性,而 Binder 由 Android 系統管理,在系統中會判斷 UID/PID 是否符合訪問權限
### Android 其他 IPC 機制
* 除了 Binder 以外,Android 仍有使用到其他 IPC 機制
1. Socket:Zygote 進程監聽 AMS 創建新進程使用 Socket
2. Mutex:Kill Process 採用信號 (Mutex) 機制
## Binder - 介紹
:::info
* Binder library 動態連結
Binder 最終會編譯成一個動態連結 Library:`libbinder.so`,方便其他進程複用
:::
* Binder 的是 C/S 架構實現分為
1. **Proxy**:對應到 Client 端,相關處理類帶有 `p` 字母
2. **Native**:對應到 Server 端,相關處理類帶有 `n` 字母
| 類 | 概述 | 說明 |
| ------ | - | -------- |
| BpRefBase | 自動釋放 ref | RefBase 子類,提供 `remote` 方法讓 獲取遠程 Binder |
| IInterface | Server | Binder Server 的基類 |
| BpInterface | Proxy | Proxy 提供 Client 使用的功能接口 |
| BnInterface | Binder Native | Native Server 實現的接口 |
| IBinder | Binder 基類 | BBinder、BpBinder 都繼承於 IBinder |
| BpBinder | Proxy | 提供 `transact` 方法來發送 Client 端請求,會由 Bpxxx 實現 |
| BBinder | Server | Server 實現的基類,提供 `onTransact` 方法,用來接收 Client 端訊息 |
| ProcessState | Process | 一個進程只有一個 ProcessState |
| IPCThreadState | Thread | 一個 Thread 在 C++ 層 |
| Parcel | Binder 包裹 | Binder 中傳遞數據、對象的包裹 |
### IBinder、BpBinder、BBinder 關係
關係圖如下
> 
* [**IBinder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/Binder.h) 繼承 `RefBase` (代表了繼承 IBinder 類的子類都具有強弱引用計數),**用來描述所有在 Binder 上傳遞的對象**;
IBinder 是 BpBinder、BBinder 的父類,主要使用的方法如下
| IBinder 方法 | 說明 |
| - | - |
| localBinder | 取得本地 Binder |
| remoteBinder | 取得遠端 Binder |
| transact | 傳送 Binder 業務 |
| queryLocalInterface | 取得本地 Binder,如果失敗則返回 Null |
| getInterfaceDescriptor | 獲取 Binder Server 描述,**也代表了 binder 服務的唯一標示** |
| isBinderAlive | 檢查 Binder 是否還存活 |
| pingBinder | 對 Binder 發送 `PING_TRANSACTION` 命令 |
:::warning
* **getInterfaceDescriptor 方法**:取得 Binder 服務的 **唯一標示**
:::
* [**BpBinder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/BpBinder.h) 繼承 IBinder:代表 **==客戶端==**
| IBinder 方法 | 說明 |
| - | - |
| create(int32_t handle) | create 方法會返回一個指向 Binder Server 的句柄 |
| transact | 提供 transact 的實做,封裝使用者要發送給 Binder Server 的數據 |
* [**BBinder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/Binder.h;l=30;bpv=1;bpt=1) 繼承 IBinder:代表 **==服務端==**
| IBinder 方法 | 說明 |
| - | - |
| onTransact | **Server 用來接收 Binder Client 的數據** |
:::warning
1. Client transact 對應 Service onTransact 方法
2. Client 端會透過 transact 傳送一個 code 給 Server 端,這兩個 **code 必須相互對應**
Code 的範圍定義在 IBinder.h
```cpp=
// IBinder.h
public:
enum {
FIRST_CALL_TRANSACTION = 0x00000001,
LAST_CALL_TRANSACTION = 0x00ffffff,
...
}
```
:::
### [BpBinder](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/BpBinder.cpp) 與 [BBinder](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/BpBinder.h) - 理解
* BpBinder 與 BBinder 都繼承於 [**IBinder.h**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/include/binder/IBinder.h) 標頭檔,兩個一一對應
1. BpBinder 代表 **客戶端**:用來 **代理客戶端 與 服務端通訊**,重點方法是 `transact`
> 
2. BBinder 代表 **服務端**:主要使用 `onTransact` 方法處理 Client 發送過來的資訊
> 
* BpBinder 可以通過 **handle (資源標識符)** 找到 BBinder 相對應的服務:詳細來說,**handle 這個整數是控制碼 (des)**,**用來找到 Binder 驅動中的 `binder_ref`**
找到 `binder_ref` 後就可以找到對應的 BinderService
```cpp=
// BpBinder.h
class BpBinder : public IBinder
{
public:
...
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0) final;
private:
static sp<BpBinder> create(int32_t handle);
struct BinderHandle {
int32_t handle;
};
// 忽略 PRC
struct RpcHandle {
sp<RpcSession> session;
uint64_t address;
};
using Handle = std::variant<BinderHandle, RpcHandle>;
Handle mHandle;
}
```
> 
### [IInterface](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/IInterface.h) - 共同接口
* 在上面我們知道 Client、Server 端的方法必須相互對應,所以最好是定義一個共用接口,**在 Binder 中這個共用接口的 ++基類就是 IInterface++**
* [**IInterface**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/IInterface.h) 是 Client、Server 接口 (使用者設定的接口) 的基類
```cpp=
// IInterface.h
class IInterface : public virtual RefBase
{
public:
IInterface();
static sp<IBinder> asBinder(const IInterface*);
static sp<IBinder> asBinder(const sp<IInterface>&);
protected:
virtual ~IInterface();
virtual IBinder* onAsBinder() = 0;
};
```
* **`onAsBinder` 方法**:會根據實現類不同代表不同意義,如果是 ^1.^ Native 實現則返回本地對象,如果是 ^2.^ Proxy 則返回 Proxy 對象
:::info
客戶端使用時就可以透過 `asBinder` 直接獲取 Binder 對象
:::
* **BnInterface、BpInterface**:兩者都是一個模板類,這個模板(`INTERFACE`) 就是 Binder 服務的基類(使用者定義的共同方法)
> 
1. BnInterface 類:BnInterface **又繼承於 BBinder,目的是為了 ++讓 Binder Server 複寫 `onTransact` 方法++**,讓 Server 處理 Client 傳來的訊息
```cpp=
// IInterface.h
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;
typedef INTERFACE BaseInterface;
protected:
virtual IBinder* onAsBinder();
};
// ----------------------------------------------------------
// Binder.h
class BBinder : public IBinder
{
public:
BBinder();
...
}
// ----------------------------------------------------------
// Binder.h
class Binder : public virtual RefBase
{
...
}
```
2. BpInterface 類:BpInterface 又**繼承於 [BpRefBase](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/Binder.h),目的是為了 ++讓 Client 端透過 `remote` 方法取得 Server 的句柄++**
:::success
* `remote` 成員指向一個 BpBinder 物件
:::
```cpp=
// IInterface.h
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
explicit BpInterface(const sp<IBinder>& remote);
typedef INTERFACE BaseInterface;
protected:
virtual IBinder* onAsBinder();
};
// -------------------------------------------------------------------
// Binder.h
class BpRefBase : public virtual RefBase
{
protected:
explicit BpRefBase(const sp<IBinder>& o);
virtual ~BpRefBase();
...
// 取得遠端 Server 句柄
inline IBinder* remote() const { return mRemote; }
inline sp<IBinder> remoteStrong() const { return sp<IBinder>::fromExisting(mRemote); }
private:
BpRefBase(const BpRefBase& o);
BpRefBase& operator=(const BpRefBase& o);
IBinder* const mRemote;
RefBase::weakref_type* mRefs;
std::atomic<int32_t> mState;
};
```
:::info
* **`BpInterface`、`BnInterface` 兩者的父類都是 RefBase,因此實作這兩個類的 Service、Client 都具有智能指標的功能**
:::
## Client 取得訪問 ServiceManager 代理
### MediaServer - Binder 服務
* 由於該篇章是介紹 Native Binder 機制,這裡選擇 MediaServer 服務來介紹,他會直接從 Native 層來向 ServiceManager 註冊
* [**MediaServer**](https://android.googlesource.com/platform/frameworks/av/+/master/media/mediaserver/main_mediaserver.cpp)#main 函數,在這個函數中我們可以看到
1. ProcessState 初始化
* 開啟 `dev/binder` 目錄下的 Binder 設備,**取得篇移值**
* 使用 mmap 為 MediaServer 進程在 Binder 驅動分配一個虛擬空間,來接收數據
2. 取得 ServiceManager 實例
* 取得 IServiceManager 對象,並用它與 ServiceManager 戶交
3. MediaServer 向 ServiceManager 註冊服務
* 用個關鍵字向 ServiceManager 註冊服務
```cpp=
// main_mediaserver.cpp
using namespace android;
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
// 1. ProcessState 初始化
sp<ProcessState> proc(ProcessState::self()); // @ ProcessState::self()
// 2. 取得 ServiceManager 實例
sp<IServiceManager> sm(defaultServiceManager()); // defaultServiceManager()
ALOGI("ServiceManager: %p", sm.get());
// 3. MediaServer 向 ServiceManager 註冊服務
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
::android::hardware::configureRpcThreadpool(16, false);
// 啟動 Binder Thread Pool
ProcessState::self()->startThreadPool();
// 將當前 Thread 加入 Binder Thread Pool
IPCThreadState::self()->joinThreadPool();
::android::hardware::joinRpcThreadpool();
}
```
### [ProcessState](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/ProcessState.cpp) - 進程單例
* **ProcessState#self()** 函數是取得 ProcessState 的 **進程單例** 對象,同時是一個進程在 Native 的代表,**==它負責開啟 `/dev/binder` 裝置==,將裝置映射到該進程中**
```cpp=
// main_mediaserver.cpp
using namespace android;
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
// 1. ProcessState 初始化
// @ ProcessState::self()
sp<ProcessState> proc(ProcessState::self());
... 省略
}
```
* ProcessState 有兩個較大重點是,^1^ 開啟 `/dev/binder` 並設定 `最大 Binder thread 數量`、^2^ 通過 `mmap` 為 binder 在該進程中分配一塊虛擬地址空間,達到內存映射的目的
> **ProcessState 是進程單例**,每個行程的 ProcessState 所開啟的 **==mmap 大小為 1M==**
* 保證同**一個進程內 ++只有一個 ProcessState 的實例++ 存在**:^1^ 使用 [**智能指針**](https://hackmd.io/nQWJhCJcQ6K-99dKIT_nmQ?view)、^2^ 並 [**加鎖**](https://hackmd.io/jh6jLfzWQZarUjsQOEQZpw?view#%E9%80%B2%E7%A8%8B%E9%80%9A%E8%A8%8A---%E9%8E%96)(上面這兩種是不同的功能唷,可以點連結去看文章)^3^ 使用 [**make**](https://hackmd.io/nQWJhCJcQ6K-99dKIT_nmQ?view#sp---make-%E5%87%BD%E6%95%B8) 創建對象
```cpp=
// /libs/binder/ProcessState.cpp
[[clang::no_destroy]] static sp<ProcessState> gProcess;
sp<ProcessState> ProcessState::self()
{
return init(kDefaultDriver, false /*requireDefault*/);
}
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{
// 1. 使用智能指針
[[clang::no_destroy]] static sp<ProcessState> gProcess;
// 2. 加鎖
[[clang::no_destroy]] static std::mutex gProcessMutex;
if (driver == nullptr) {
// 一般不會進來
std::lock_guard<std::mutex> l(gProcessMutex);
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);
driver = "/dev/binder"; // binder 驅動
}
std::lock_guard<std::mutex> l(gProcessMutex);
// 3. 創建 ProcessState 對象
gProcess = sp<ProcessState>::make(driver);
});
...
return gProcess;
}
```
### ProcessState - open 開啟 Binder
* 保證只有 **ProcessState 對象創建時,才開啟 Binder 驅動(open) & 內存映射(mmap)** 應對了 **++一個進程只會做一次 Binder 內存映射++**
* **執行 `open_driver` 函數**:透過 `open` 開啟 Binder 驅動後,`/dev/binder` 就映射到內核分頁中,返回檔案描述 (FD) 並使用 `mDriverFD` 存起來
:::info
* open 函數 概述
1. 映射為驅動的 `binder_open` 函數
2. 在應用呼叫 open 開啟 Binder 驅動後,就會在內核創建一個 `binder_proc` 結構,並初始化
3. **這樣 Kernel 就擁有該應用進程的訊息**
:::
* 執行 [**`mmap` 函數**](https://hackmd.io/Rkz2NOVoRdWu5v6Nkb4cxQ#%E9%80%B2%E7%A8%8B%E9%80%9A%E8%A8%8A---mmap-%E5%87%BD%E6%95%B8):將核心開闢一塊空間,將分頁的 Binder 記憶體映射到進程中
```cpp=
// /libs/binder/ProcessState.cpp
// 接近 1M 的空間
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
// binder 支持的最大 Thread 數量設定為 15
#define DEFAULT_MAX_BINDER_THREADS 15
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
, mDriverFD(open_driver(driver)) // 注意 open_driver 函數
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mWaitingForThreads(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS) // MAX Thread 數量
, mStarvationStartTimeMs(0)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
, mCallRestriction(CallRestriction::NONE)
{
// 成功開啟 /dev/binder
if (mDriverFD >= 0) {
// 開始執行 mmap 函數 (執行 Kernal 層)
// sm 也是服務端
mVMStart = mmap(
nullptr,
BINDER_VM_SIZE, // 文件映射內存大小,接近 1M 的空間
PROT_READ,
MAP_PRIVATE | MAP_NORESERVE,
mDriverFD, // 指定該 Binder 的 offect
0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
}
}
static int open_driver(const char *driver)
{
// 開啟 binder 驅動
// fd 就是 offect
int fd = open(driver, O_RDWR | O_CLOEXEC);
... 省略錯誤處理
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; // 15 個為上限
// 寫入設定 binder thread 的上限
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
... 省略部分
return fd;
}
```
:::success
* Intel x86 CPU 提供了 **0 ~ 3 共 4 個特權權限**,**特權數字越小,權限越高** (0 最高、3 最小),而 Linux 將該機制規劃為
1. Kernel 權限至為 0 最高
2. User 權限至為 3 最低
這樣進程在 User 模式下,**不經由系統調用 (system call) 就無法主動訪問 Kernel 空間**,這也就起到了保護作用
:::
### 取得 IServiceManager - 創建 BpBinder 代理
:::info
BpBinder 可以記憶為與 Binder 的代理(Proxy),而 **現在的步驟就是取得與 ServiceManager 通訊的代理對象**
\-----------------------------------------------------------------------
ServiceManager 是一個特別的服務,**它的控制碼 (handle) 一直是 0,因此它也省去了去 BinderDriver 中找 binder_ref 的流程**
:::
* **defaultServiceManager 函數**:MediaServer 中有呼叫這個函數,並透過該函數取得 IServiceManager 實例,現在就來分析這個函數
```cpp=
// main_mediaserver.cpp
#include <binder/IServiceManager.h>
using namespace android;
int main(int argc __unused, char **argv __unused)
{
...
// 2. 取得 ServiceManager 實例
// @ 分析 defaultServiceManager() 函數
sp<IServiceManager> sm(defaultServiceManager());
}
```
* defaultServiceManager 定義在 [**IServiceManager.h**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/include/binder/IServiceManager.h) 中,實現在 [**IServiceManager.cpp**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/IServiceManager.cpp),在這裡會透過 **==`interface_cast` 函數== 取得 IServiceManager ++代理物件++ 實例**,接著繼續分析
:::success
* 這裡使用全局變量 `gDefaultServiceManager` 保證 **整個進程只有一個 ServiceManager 代理物件**
:::
```cpp=
// IServiceManager.h
sp<IServiceManager> defaultServiceManager();
// 全局變量
[[clang::no_destroy]] static std::once_flag gSmOnce;
[[clang::no_destroy]] static sp<IServiceManager> gDefaultServiceManager;
sp<IServiceManager> defaultServiceManager()
{
std::call_once(gSmOnce, []() {
sp<AidlServiceManager> sm = nullptr;
// @ 分析 getContextObject 方法
// @ 分析 interface_cast
while (sm == nullptr) {
sm = interface_cast<AidlServiceManager>(
// 返回的是 IBinder 對象
// ProcessState::self() 是取得進程單例
ProcessState::self()->getContextObject(nullptr)
);
if (sm == nullptr) {
ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str());
sleep(1);
}
}
gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
});
return gDefaultServiceManager;
}
```
1. [**ProcessState**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/ProcessState.cpp)#getContextObject 方法呼叫 `getStrongProxyForHandle` 並傳入 0(這個 0 其實就是取得 ServiceManager 的標示),分析 `getStrongProxyForHandle` 方法
```cpp=
// ProcessState.cpp
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
// @ 分析 getStrongProxyForHandle
sp<IBinder> context = getStrongProxyForHandle(0);
...
return context;
}
```
1. 查看是否有 ServiceManager 緩存,如果有的話直接返回
2. 透過 `lookupHandleLocked` 方法,搜尋 handle 為 0 的節點,**如果不存在該節點,則會創建節點後返回**
> 節點為 `handle_entry` 結構
:::info
* 每個進程會有一個 `mHandleToObject` 清單,用來儲存 **Key:控制碼、Value:代理物件** 的列表
```cpp=
class ProcessState : public virtual RefBase
{
private:
struct handle_entry {
IBinder* binder; // 指向代理物件
RefBase::weakref_type* refs; // 指向代理物件的計數
};
Vector<handle_entry>mHandleToObject;
}
```
:::
3. 取得 handle_entry 結構內的 IBinder,並且以下有 **兩個狀況會創建新的 IBinder 對象**
* 直接沒有 IBinder 成員
* 無法對該 IBinder 成員增加弱引用次數
> 代表該代理物件已經死亡
:::success
目前要創建的 IBinder 對象是 [**BpBinder**](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/include/binder/BpBinder.h),用來訪問 ServiceManager 進程
:::
```cpp=
// ProcessState.cpp
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
// 1. 緩存 ServiceManager 對象
if (handle == 0 && the_context_object != nullptr) return the_context_object;
// 2. 搜尋 handle 為 0 的節點,**如果不存在該節點,則會創建節點後返回**
handle_entry* e = lookupHandleLocked(handle);
if (e != nullptr) {
// 取得節點的內容 IBinder
IBinder* b = e->binder;
// 創建 BpBinder 的條件 兩條件
// a. 找不到對應的 BpBinder(e->binder) 指針
// b. 無法對這個 BpBinder(e->binder) 增加 weakreference
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
IPCThreadState* ipc = IPCThreadState::self();
CallRestriction originalCallRestriction = ipc->getCallRestriction();
ipc->setCallRestriction(CallRestriction::NONE);
Parcel data;
status_t status = ipc->transact(
0, IBinder::PING_TRANSACTION, data, nullptr, 0);
ipc->setCallRestriction(originalCallRestriction);
if (status == DEAD_OBJECT)
return nullptr;
}
// 創建 BpBinder 對象,handle 為 0,作為指向 ServiceManager 的句柄
sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle);
e->binder = b.get();
if (b) e->refs = b->getWeakRefs();
result = b;
} else { // binder 成員不為 null
result.force_set(b);
// 取得後減少弱引用次數 (因為前面有測試增加弱引用計數,返回前就需減掉)
e->refs->decWeak(this);
}
}
return result;
}
// 這裡保存了這個進程已建立的 Binder 相關訊息
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
// mHandleToObject 類型 Vector<handle_entry>;
const size_t N=mHandleToObject.size();
if (N <= (size_t)handle) {
handle_entry e;
e.binder = nullptr;
e.refs = nullptr;
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
if (err < NO_ERROR) return nullptr;
}
// 若是 Vector 表中沒有相應節點,則會自動添加一個
return &mHandleToObject.editItemAt(handle);
}
```
流程圖如下
> 
2. interface_cast 方法:另外一小節分析
### 創建 [IServiceManager](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/include/binder/IServiceManager.h) - BpServiceManager 對象
:::info
IServiceManager 功能:主要放有 ServiceManager 的所有函數,對應到 Java 層也會有相同的方法,像是 `getService`、`checkService`、`addService`... 等等
:::
* 在上面我們知道 ProcessState#getContextObject 返回的是一個 IBinder(**BpBinder**)對象,而 IBinder 對象如何返回一個 IServiceManager 呢?
這就需要透過 **`interface_cast` 函數**
```cpp=
// IServiceManager.cpp
using AidlServiceManager = android::os::IServiceManager;
// cache
sp<IServiceManager> defaultServiceManager();
[[clang::no_destroy]] static sp<IServiceManager> gDefaultServiceManager;
sp<IServiceManager> defaultServiceManager()
{
std::call_once(gSmOnce, []() {
sp<AidlServiceManager> sm = nullptr;
while (sm == nullptr) {
// @ 分析 interface_cast 方法
// AidlServiceManager 就是 ++IServiceManager++
sm = interface_cast<AidlServiceManager>(
// 返回的是 IBinder 對象
ProcessState::self()->getContextObject(nullptr)
);
...
}
gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
});
return gDefaultServiceManager;
}
```
> 
* [**IInterface**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/include/binder/IInterface.h)#**interface_cast** 方法使用了 **C++ 的 ==模板設計==**
```cpp=
// IInterface.h
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
// 傳入 AidlServiceManager
// using AidlServiceManager = android::os::IServiceManager;
return INTERFACE::asInterface(obj);
}
// -------------------------------------------------------
// 目前傳入 INTERFACE => IServiceManager 標示
// 以下我們手動轉換
inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
{
return IServiceManager::asInterface(obj);
}
```
* INTERFACE::asInterface 宏方法宣告 & 宏定義
:::danger
* 最新版本有提示 Binder interface 如果 **使用 ++宏定義常常會導致錯誤++**,**最好的方法是定義一個 `.aidl` 文件**,讓其自動生成
> 
* 但這並不影響我們研究,所以這裡我們仍看看宏定義
:::
1. **DECLARE_META_INTERFACE 宏**:透過宏(define)定義在 IInterface.h 中
```cpp=
// IInterface.h
#define DECLARE_META_INTERFACE(INTERFACE) \
public: \
// 該介面的唯一描述符號,之後會定義為傳入的 "INTERFACE"
static const ::android::String16 descriptor; \
// 宣告 asInterface 方法
static ::android::sp<I##INTERFACE> asInterface(const ::android::sp<::android::IBinder>& obj); \
// 宣告 getInterfaceDescriptor 方法
virtual const ::android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##INTERFACE(); \
static bool setDefaultImpl(::android::sp<I##INTERFACE> impl); \
static const ::android::sp<I##INTERFACE>& getDefaultImpl(); \
\
private: \
static ::android::sp<I##INTERFACE> default_impl; \
\
```
* 透過 **DECLARE_META_INTERFACE** 可以翻譯成如下
| 標誌 | 傳入 & 轉換 |
| -------- | -------- |
| INTERFACE | IServiceManager |
```cpp=
// IInterface.h
public:
static const ::android::String16 descriptor;
static ::android::sp<IServiceManager> asInterface(const ::android::sp<::android::IBinder>& obj);
virtual const ::android::String16& getInterfaceDescriptor() const;
IServiceManager();
virtual ~IServiceManager();
static bool setDefaultImpl(::android::sp<IServiceManager> impl);
static const ::android::sp<IServiceManager>& getDefaultImpl();
private:
static ::android::sp<IServiceManager> default_impl;
```
2. **IMPLEMENT_META_INTERFACE 宏**:這裡就有 **提示不要用宏定義 binder interface**
:::info
* `IMPLEMENT_META_INTERFACE` 與 `DECLARE_META_INTERFACE` 宏對應,**它是 `DECLARE_META_INTERFACE` 的實現**
:::
```cpp=
// IInterface.h
// 查看 DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE 宏
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)
// 查看 DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0 宏
#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const ::android::StaticString16 I##INTERFACE##_descriptor_static_str16( \
__IINTF_CONCAT(u, NAME)); \
const ::android::String16 I##INTERFACE::descriptor(I##INTERFACE##_descriptor_static_str16); \
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(I##INTERFACE, I##INTERFACE, Bp##INTERFACE)
// 宏定義
#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(ITYPE, INAME, BPTYPE) \
const ::android::String16& ITYPE::getInterfaceDescriptor() const { return ITYPE::descriptor; } \
::android::sp<ITYPE> ITYPE::asInterface(const ::android::sp<::android::IBinder>& obj) { \
::android::sp<ITYPE> intr; \
// getInterfaceDescriptor 實作方案
if (obj != nullptr) { \
intr = ::android::sp<ITYPE>::cast(obj->queryLocalInterface(ITYPE::descriptor)); \
if (intr == nullptr) { \
intr = ::android::sp<BPTYPE>::make(obj); \
} \
} \
return intr; \
} \
::android::sp<ITYPE> ITYPE::default_impl; \
bool ITYPE::setDefaultImpl(::android::sp<ITYPE> impl) { \
/* Only one user of this interface can use this function */ \
/* at a time. This is a heuristic to detect if two different */ \
/* users in the same process use this function. */ \
assert(!ITYPE::default_impl); \
if (impl) { \
ITYPE::default_impl = std::move(impl); \
return true; \
} \
return false; \
} \
const ::android::sp<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; } \
ITYPE::INAME() {} \
ITYPE::~INAME() {}
```
* 可以翻譯成如下(有 2 個 define 宏),並可以看到 **asInterface 主要是 ==創建 BpServiceManager 對象==**
| define 宏 | 標誌 | 傳入 & 轉換 |
| - | -------- | -------- |
| IMPLEMENT_META_INTERFACE | INTERFACE | IServiceManager |
| IMPLEMENT_META_INTERFACE | NAME | android.os.IServiceManager |
| - | - | - |
| DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0 | ITYPE | IServiceManager |
| DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0 | INAME | IServiceManager |
| DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0 | BPTYPE | BpServiceManager |
```cpp=
// ServiceManager 轉換的程式如下
const ::android::StaticString16
IServiceManager_descriptor_static_str16(__IINTF_CONCAT(u, NAME));
const ::android::String16 IServiceManager
::descriptor(IServiceManager_descriptor_static_str16);
const ::android::String16& IServiceManager
::getInterfaceDescriptor() const { return IServiceManager::descriptor; }
::android::sp<IServiceManager> IServiceManager::asInterface(const ::android::sp<::android::IBinder>& obj) {
::android::sp<IServiceManager> intr;
if (obj != nullptr) {
intr = ::android::sp<IServiceManager>::cast(obj->queryLocalInterface(IServiceManager::descriptor));
if (intr == nullptr) {
// obj 對象是 BpBinder
intr = ::android::sp<BpServiceManager>::make(obj);
}
}
return intr;
}
::android::sp<IServiceManager> IServiceManager::default_impl; .
bool IServiceManager::setDefaultImpl(::android::sp<IServiceManager> impl) {
assert(!IServiceManager::default_impl);
if (impl) {
IServiceManager::default_impl = std::move(impl);
return true;
}
return false;
}
const ::android::sp<IServiceManager>& IServiceManager::getDefaultImpl() { return IServiceManager::default_impl; }
IServiceManager::IServiceManager() {}
IServiceManager::~IServiceManager() {}
```
* 這時我們可以知道 **ServiceManager#asInterface 方法主要是 ++創建 BpServiceManager 對象++**,並且它接收的參數是 ProcessState::getContextObject 返回的的 **==BpBinder==**
* [**BpServiceManager**](https://android.googlesource.com/platform/frameworks/native/+/jb-dev/libs/binder/IServiceManager.cpp) 的實做在新版本中也被移除,猜測應該也是由 aidl 協助創建,該類會繼承於 BpInterface 接口,接著我們分析 [**BpInterface**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/include/binder/IInterface.h#133)、[**BpRefBase**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/Binder.cpp)
```java=
// IServiceManager.cpp
// 舊版 BpServiceManager
// @ 分析 BpInterface 類
class BpServiceManager : public BpInterface<IServiceManager>
{
public:
BpServiceManager(const sp<IBinder>& impl)
: BpInterface<IServiceManager>(impl)
{ }
// -----------------------------------------------------------------------
// IInterface.h
// @ 分析 BpRefBase 類
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
explicit BpInterface(const sp<IBinder>& remote);
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
};
// -----------------------------------------------------------------------
// Binder.cpp
BpRefBase::BpRefBase(const sp<IBinder>& o) // o => BpServiceManager => BpBinder
: mRemote(o.get()), mRefs(nullptr), mState(0)
{
// 由弱引用計數來控制該對象生命週期
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
if (mRemote) {
mRemote->incStrong(this); // Removed on first IncStrong().
mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
}
}
```
> 
* 小結論:^1.^ BpServiceManager#mRemote 其實就是 **指向 BpBinder 對象**,^2.^ BpServiceManager 實現了 IServiceManager 的接口方法,並透過 **調用 mRemote 來實現 BpBinder 通訊**
:::success
* BpServiceManager 的功能相當於一個 **==OOP 代理模式==**,透過訪問 BpServiceManager 來訪問 BpBinder
:::
> 
### IServiceManager 關係 UML
* 這裡我們提及較為重要的類、還有它們的主要功能
| 類 | 產生 | 功能說明 |
| ---- | ---- | -------- |
| BpRefBase | 實體 | 存有 IBinder 對象(BpBinder) |
| BpServiceManager | 實體、aidl 產生 | 用來代理 BpBinder |
| IInterface | 實體 | 定義許多可使用的宏 |
| IServiceManager | 宏、aidl 產生 | IServiceManager 透過 `asInterface` 函數來取得 BpBinder |
| BpBinder | 實體 | Client 端使用的 Binder |
| BBinder | 實體 | Server 端使用的 Binder |
UML 關係圖可以看到每個類之間的關係
> 
## Client 向 ServiceManager 註冊
```cpp=
// main_mediaserver.cpp
using namespace android;
int main(int argc __unused, char **argv __unused)
{
... 省略部份
// MediaServer 向 ServiceManager 註冊服務
MediaPlayerService::instantiate();
... 省略部份
}
```
`instantiate` 函數註冊在 [**MediaPlayerService**](https://android.googlesource.com/platform/frameworks/av/+/master/media/libmediaplayerservice/MediaPlayerService.cpp) 實做
```cpp=
// MediaPlayerService.cpp
void MediaPlayerService::instantiate() {
// 透過 `defaultServiceManager` 函數
// 取得訪問 ServiceManager 的代理
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
```
* 從 defaultServiceManager 可以知道以下事情
1. 取得 BpServiceManager 對象(訪問 ServiceManager 的代理)
2. 透過 [**BpServiceManager**](https://android.googlesource.com/platform/frameworks/native/+/jb-dev/libs/binder/IServiceManager.cpp) 呼叫 BpBinder#addService 方法
3. 傳入參數 "`media.player`" & "`MediaPlayerService 對象`"
> 類似於 Key/Value 完成註冊
* 訪問 Binder 驅動 - 指令流程如下
> 
### [IServiceManager](https://android.googlesource.com/platform/frameworks/native/+/jb-dev/libs/binder/IServiceManager.cpp) - addService 註冊
* 由於新版沒有 BpServiceManager 實做,所以我們參考舊版是如何實現
| Parcel 打包方法 | 實際值 |
| -------- | -------- |
| writeInterfaceToken | `android.os.IServiceManager` |
| writeString16 | `media.player` |
| writeStrongBinder | MediaPlayerService 對象 (IBinder 指針) |
```java=
// IServiceManager.cpp
class BpServiceManager : public BpInterface<IServiceManager>
{
public:
BpServiceManager(const sp<IBinder>& impl)
: BpInterface<IServiceManager>(impl)
{ }
// default 抽象實做
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated)
{
Parcel data, reply;
// 1. "android.os.IServiceManager"
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
// 使用者傳入 "media.player"
data.writeString16(name);
// MediaPlayerService 對象,包裝成 `flat_binder_object`
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
// 這裡取得的 remote 就是 BpBinder
// @ 追蹤 transact 方法
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
}
```
1. `writeInterfaceToken` 函數:會將 **介面 String 寫入 Parcel 包中**;目前就是寫入 `android.os.IServiceManager` 字符串
```cpp=
// Parcel.cpp
status_t Parcel::writeInterfaceToken(const String16& interface)
{
return writeInterfaceToken(interface.string(), interface.size());
}
status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
... 省略部分
// 將描述寫入
return writeString16(str, len);
}
```
:::success
* IServiceManager::[**getInterfaceDescriptor**](https://cs.android.com/android/platform/superproject/+/master:out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_x86_64_silvermont_shared/gen/aidl/android/os/IServiceManager.cpp) 定義為: `"android.os.IServiceManager"` (系統中唯一描述)
```cpp=
// IServiceManager.cpp
namespace android {
namespace os {
// 宏定義 `DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE`
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(
ServiceManager,
"android.os.IServiceManager")
} // namespace os
} // namespace android
```
:::
2. `writeStrongBinder` 函數:將 Server 元件(地址) 包裝成 `flat_binder_object` 結構,主要 **記錄本地 Server、其弱引用地址**
```cpp=
// Parcel.cpp
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
// @ 查看 flattenBinder
return flattenBinder(val);
}
status_t Parcel::flattenBinder(const sp<IBinder>& binder) {
BBinder* local = nullptr;
// 查看是否是本地 Server
if (binder) local = binder->localBinder();
if (local) local->setParceled();
... 省略 RPC
flat_binder_object obj;
...
if (binder != nullptr) {
if (!local) {
// 非本地 Service ... 目前是本地 Service 所以暫不關注
} else {
// 當前狀況 <<<<
... 省略部分
obj.hdr.type = BINDER_TYPE_BINDER; // 本地 Service 標示
// 取得本地 Service 弱引用的地址
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
// 取得本地 Service 地址
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
...
}
...
// @ 查看 writeObject
status_t status = writeObject(obj, false);
...
return finishFlattenBinder(binder);
...
}
```
:::success
* Parcel#`writeObject` 函數詳解請看另一篇 [**Android-Parcel**](https://hackmd.io/Qr4dm2XsSpyhMeB5dIePyA#Android-Parcel) 介紹
:::
* BpServiceManager#`addService` 方法:使用的 **remote** 就是 [**BpBinder 對象**](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/BpBinder.cpp),所以其實它是在呼叫 BpBinder#**transact** 方法
```cpp=
// BpBinder.cpp
status_t BpBinder::transact(
uint32_t code, // ADD_SERVICE_TRANSACTION (給目標 Service 的控制命令)
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 方法
// binderHandle 目前返回是 0 (訪問 ServiceManager 的 handle 值)
status = IPCThreadState::selTextf()->
transact(binderHandle(), code, data, reply, flags);
}
... 省略部份
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
```
> 
### [IPCThreadState](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/IPCThreadState.cpp) - TLS 介紹
```cpp=
// IPCThreadState.h
class IPCThreadState
{
public:
...
static IPCThreadState* self(); // 取得 Thread 單例
// 與 Binder 驅動互動
status_t transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
private:
...
// 與 Binder 驅動互動
status_t talkWithDriver(bool doReceive=true);
// 進程單例
const sp<ProcessState> mProcess;
}
```
* **IPCThreadState 是使用一種 ++TLS 機制++,它的全名是 Thread local storage,這是一種 ++線程單例++ 機制**,**每個 Thread 中只會有一個實例**,不同 Thread 之間不共享
:::info
atomic 類是使用 CAS 機制
:::
```cpp=
// IPCThreadState.cpp
static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
// atomic 類
static std::atomic<bool> gHaveTLS(false);
static pthread_key_t gTLS = 0;
IPCThreadState* IPCThreadState::self()
{
// 判斷是否已加載過
if (gHaveTLS.load(std::memory_order_acquire)) {
restart:
const pthread_key_t k = gTLS
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
// 已創建過直接返回 cache 對象
if (st) return st;
// 尚未創建過,創建對象
return new IPCThreadState;
...
// mutex 鎖
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS.load(std::memory_order_relaxed)) {
int key_create_value = pthread_key_create(&gTLS, threadDestructor);
// 判斷是否成功 (0 代表成功)
if (key_create_value != 0) {
pthread_mutex_unlock(&gTLSMutex);
ALOGW("IPCThreadState::self() unable to create TLS key, expect a crash: %s\n",
strerror(key_create_value));
return nullptr;
}
gHaveTLS.store(true, std::memory_order_release);
}
pthread_mutex_unlock(&gTLSMutex);
// 去 restart tag 加載並返回
goto restart;
}
```
* IPCThreadState 建構函數,將 IPCThreadState 對象設置為 TLS、並設定傳輸 & 接收 Binder data 的大小
```cpp=
// IPCThreadState.cpp
static pthread_key_t gTLS = 0;
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()), // ProcessState 進程單例
mServingStackPointer(nullptr),
mServingStackPointerGuard(nullptr),
mWorkSource(kUnsetWorkSource),
mPropagateWorkSource(false),
mIsLooper(false),
mIsFlushing(false),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0),
mCallRestriction(mProcess->mCallRestriction) {
// 設置 TLS,將獲取的 pthread_key_t、自身傳入
pthread_setspecific(gTLS, this);
clearCaller();
// 預設 Binder 傳遞的大小 (單位 byte)
mIn.setDataCapacity(256); // 接收 Binder data 256 byte
mOut.setDataCapacity(256); // 傳輸 Binder data 256 byte
}
// -----------------------------------------------------------------
// IPCThreadState.h
class IPCThreadState
{
... 省略部份
private:
... 省略部份
// Parcel 對象
Parcel mIn;
Parcel mOut;
};
```
:::success
* 每個 Thread 都有 256 byte 的 in/out Parcel Buffer,當容量不足時會自動擴充
:::
### [IPCThreadState](https://android.googlesource.com/platform/frameworks/native/+/master/libs/binder/IPCThreadState.cpp) - transact 傳送命令
* 在了解 IPCThreadState 後,我們接著來看 BpServiceManager#addService 所使用到的 `transact` 函數,這裡有幾個重要函數
| 函數名 | 功能 |
| -------- | -------- |
| writeTransactionData | **組裝 `binder_transaction_data` 數據** |
| waitForResponse | 將數據傳到 BinderDriver 並等待 BinderDriver (kernel) 回覆 |
:::danger
* Parcel 可以在不同進程間傳輸資訊,請先看 [**Parcel 打包**](https://hackmd.io/Qr4dm2XsSpyhMeB5dIePyA?view#Parcel---Active-Object) IBinder 物件,對 Service 判斷,並設定不同的 Type (這個 Type 會有關於 Binder Kernel 如何判斷轉換)
:::
```cpp=
// IPCThreadState.cpp
status_t IPCThreadState::transact(
int32_t handle, // 0 (目標 handle 0 為 ServiceManager)
uint32_t code, // ADD_SERVICE_TRANSACTION
const Parcel& data, // 給 BinderDriver 的資料
Parcel* reply, // BinderDriver 回覆的資料
uint32_t flags) // 是否同步傳輸
{
... log 訊息
status_t err;
flags |= TF_ACCEPT_FDS; // 允許 Server 回傳結果中帶有 FD ( 檔案描述符
... log 訊息
// @ writeTransactionData 函數
// 傳遞 cmd 為 BC_TRANSACTION
err = writeTransactionData(BC_TRANSACTION,
flags,
handle, // 0 (ServiceManager 固定)
code, // ADD_SERVICE_TRANSACTION
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;
}
```
:::success
* Binder Kernel **指令取名方式:**傳向 Binder Kernel 的指令是有規則的**
`BC_` 開頭的是向 Binder Kernel 發送命令
`BR_` 則是 Binder kernel 回覆命令給使用端
:::
### writeTransactionData - 打包數據給 BinderDriver
:::info
主要使用結構 `binder_transaction_data`
:::
* IPCThreadState#**`writeTransactionData` 函數**:首先會準備要傳向 Binder kernel 的數據結構 `(binder_transaction_data)` 結構,對該結構填充數據
| binder_transaction_data 成員 | 功能 | 當前數據 |
| -------- | -------- | - |
| cmd | Binder kernel 需要處理的指令 | `BC_TRANSACTION` |
| handle | 標示要傳遞的目標 | `0` (ServiceManager) |
| code | 接收進程會收到的命令 | 傳遞給 ServiceManager 命令 `ADD_SERVICE_TRANSACTION` |
```cpp=
// IPCThreadState.cpp
// 傳遞 cmd 為 BC_TRANSACTION
status_t IPCThreadState::writeTransactionData(int32_t cmd, // BC_TRANSACTION
uint32_t binderFlags,
int32_t handle, // 0
uint32_t code, // ADD_SERVICE_TRANSACTION
const Parcel& data, // 使用者要傳輸給 BinderDriver 的數據
status_t* statusBuffer)
{
binder_transaction_data tr;
// 不要將未初始化的堆棧數據傳遞給遠程進程
tr.target.ptr = 0;
tr.target.handle = handle; // 目前是 0
tr.code = code; // 目前是 ADD_SERVICE_TRANSACTION
tr.flags = binderFlags; // TF_ACCEPT_FDS
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(); // 將 data 指標賦予 buffer
// binder 的偏移 (BinderServer 的所有紀錄)
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
...
} else {
...
}
// 將給 BinderKernel 的命令寫入 mOut 中
mOut.writeInt32(cmd); // 目前是 BC_TRANSACTION
// 將數據複製進 tr 中
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
// --------------------------------------------------------------
// Parcel.cpp
status_t Parcel::write(const void* data, size_t len)
{
...
void* const d = writeInplace(len);
if (d) {
// d 複製到 data 中
memcpy(d, data, len); // 直接使用 memcpy 將數據複製進去
return NO_ERROR;
}
return mError;
}
```
:::info
* **`BC_TRANSACTION` 指令位置** ?
由於它在 Parcel 最後被加入,所以 `BC_TRANSACTION` 放置在 `binder_transaction_data` 數據後
> 
:::
* 到目前為止我們可以看到 UserSpace 使用者將 Parcel 數據打包進 `binder_transaction_data` 結構中,結構如下
```c=
// binder.h
struct binder_transaction_data {
// 不同狀態下代表了不同含意
union {
__u32 handle; // 控制碼
binder_uintptr_t ptr;
} target;
// User 另外指定的參數
binder_uintptr_t cookie;
// 傳遞給 BinderService 的命令,與 BinderDriver 無關
__u32 code;
// flags 定義如 transaction_flags,代表這次通訊的特徵
__u32 flags;
// 以下兩個是 Binder 驅動程式填寫
__kernel_pid_t sender_pid; // 發起請求的 進程 ID
uid_t sender_euid; // 發起請求的 UID
binder_size_t data_size; // 描述 data 大小
binder_size_t offsets_size; // 描述 data 偏移
union {
// 資料較大時須使用 ptr
struct {
binder_uintptr_t buffer; // 指向緩存空間
binder_uintptr_t offsets;
} ptr;
__u8 buf[8]; // 資料較少時,可以直接使用
} data;
};
```
總結一下在該階段中打包好的 binder_transaction_data (簡稱 TRD) 結構如下
| TRD 成員 | 數據 | 補充 |
| -------- | -------- | -------- |
| target.handle | 0 | 目標控制碼為 0,也就是 ServiceManager |
| code | ADD_SERVICE_TRANSACTION | 給 ServiceManager 的命令 |
| flags | TF_ACCEPT_FDS | |
| data_size | sizeof(int32_t) | |
| - | strlen("android.os.IServiceManager") | |
| - | sizeof(flat_binder_object) | |
| - | strlen("media.player") | 要註冊的目標 Service |
| offsets_size | sizeof(size_t) | |
| data.ptr.buffer | "android.os.IServiceManager" | |
| - | flat_binder_object | 下表會再說明內容 |
| - | "media.player" | |
| data.ptr.offsets | sizeof(int32_t) | |
| - | strlen("android.os.IServiceManager") | |
| - | strlen("media.player") | |
* 再針對 `flat_binder_object` 看看其內容
```c=
// binder.h
struct flat_binder_object {
struct binder_object_header hdr;
__u32 flags; // 只有是 LocalBinder 時才有意義
// 對象 共同體
union {
binder_uintptr_t binder; // Local Service 同 process 對象
__u32 handle; // 遠端跨 process 對象 (控制碼)
};
binder_uintptr_t cookie; // Local Service 時指向 Binder 的實體位置
};
struct binder_object_header {
__u32 type;
};
```
| flat_binder_object | 數據 | 補充 |
| -------- | -------- | -------- |
| type | BINDER_TYPE_BINDER | 本地 Service |
| flag | 0x7f \| FLAT_BINDER_FLAG_ACCEPTS_FDS | |
| binder | `localBinder()` | 本地服務的地址 |
| cookie | `localBinder()->getWeakRefs` | 本地服務弱計數的地址 |
### talkWithDriver - 與 BinderDriver 通訊
:::info
主要使用結構 `binder_write_read`
:::
* **IPCThreadState#`waitForResponse` 函數**:主要是與 BinderDriver 通訊,並處理 Binder kernel 的回覆(處理以 `BR_` 開頭的命令),其中有兩個較重要的函數
> 該函數不只讀,也會寫指令
| 函數名 | 功能 |
| - | - |
| talkWithDriver | 對 BinderDriver 寫入(mOut) or 讀取(mIn) |
| executeCommand | 處理從 BinderDriver (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;
// 到這裡就代表 BinderDriver 有回覆 (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:
if (!reply && !acquireResult) goto finish;
break;
... 其他 case
default:
// 處理各種命令
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
...
return err;
}
```
* **IPCThreadState#`talkWithDriver` 函數**:真正與 BinderDriver 通訊的函數;目前要處理的 **命令是 `BC_TRANSACTION`**,通知 BinderDriver 傳送資料
```cpp=
// IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive) // doReceive = true
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
binder_write_read bwr
// 判斷 mIn#position 位置 是否有移動 (也就是 BinderDriver 是否有傳資料給 Thread)
// 有移動並大於 dataSize 代表有資料
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// 1. doReceive 是否接收 BinderDriver 資料
// 2. needRead 在讀取 BinderDriver 資料時我們不想寫入任何 mOut 資料
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
// 如果 outAvail 為 0,就不會傳送資料給 BinderDriver
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data(); // 寫入資料
// 目前狀況是 doReceive = true
if (doReceive && needRead) {
// needRead = true
// BinderDriver 有資料要讀取
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
// 不讀 BinderDriver 資料
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);
if (err >= NO_ERROR) { // 以下為沒錯誤
if (bwr.write_consumed > 0) { //
if (bwr.write_consumed < mOut.dataSize())
... BinderDriver 尚未處理完資料
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
if (bwr.read_consumed > 0) {
// 有資料要讀取,更新 DataPosition & buf 指標
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
... log msg
return NO_ERROR;
}
return err;
}
```
* 這裡就會接觸到 BinderDriver (kernel 層) 的 ioctl 函數,到這裡就超過 Binder Native 的領域,我們先知道 BinderDriver 會紀錄傳入的 **`handle 標示` & `name 服務名稱`** ... 等等資訊
1. 當前 handle 是 0 (裝在 mOut 中)
2. 當前服務名 name 是 "`android.os.IServiceManager`" (裝在 mOut 中)
3. 並且帶有兩個命令
| 命令 | 處理對象 |
| - | - |
| ADD_SERVICE_TRANSACTION | ServiceManager |
| BC_TRANSACTION | BinderDriver |
:::success
* 後續請參考 [**Binder - Kernel 驅動分析**](https://hackmd.io/8E1AyMAgRzym3g6ktNV37Q#Binder---Kernel-%E9%A9%85%E5%8B%95%E5%88%86%E6%9E%90),會說明 BinderDriver#**binder_ioctl** 函數
:::
> 
## 註冊服務 - 命令過程
* 之前有說過 Binder 是 Clien/Server 架構,在這裡我們所舉的例子
1. Client 是 MediaPlayerService:**註冊過程是發生在 Client 端**,透過 Proxy 去訪問 BinderKernel
2. Server 是 ServiceManager:用於添加系統
簡化 Binder 命令如下,**通過 ++協議命令++** 來完成系統服務註冊
> 
詳細命令流程
> 
* 到這裡你會涉及到許多麼命令,這有點類似於 **網路封包**,指令是一層一層解析
> 
## Appendix & FAQ
:::info
跟沒有借東西數到 10
限制當起跑點
:::
###### tags: `Binder` `Android 系統`