Android 12 系統源碼分析 | Native Binder 代碼變遷
注:廣義上 Native Binder 可理解為包含 VND,HW,RPC 等內容,本文所討論的 Native Binder 指的僅是 servicemanager 服務程序及 libbinder 中相關代碼,不做廣義的延伸。
一、前言
servicemanager 程序(以下簡稱 SM )是 Android 系統 Binder 模塊重要的組成部分,扮演着類似 C/S 架構中的 DNS 服務器的角色,提供服務增查和權限管理等功能支撐。
在 Android 11 之前的版本里,SM 是面向 Binder 驅動編程,直接使用 open、mmap、ioctl 等 API 與 Binder 驅動交互。而從 Android 11 開始,SM 放棄使用這些較底層的接口,轉向 libbinder 庫和 AIDL。標志性的提交如下,該提交奠定了新的 SM 架構基礎,此后多次提交對此進行完善填充。
frameworks/native
servicemanager: use libbinder
Bug: 135768100
Test: boot
Test: servicemanager_test
Change-Id: I9d657b6c0d0be0f763b6d54e0e6c6bc1c1e3fc7a
(cherry picked from commit 3e092daa14c63831d76d3ad6e56b2919a0523536)
smoreland@google.com(作者)
提交日期2019-07-09 AM 9:54
本文代碼基於 Android 12 ,以 SM 為主視角,從架構和情景流程上帶大家認識新的 Native Binder。
二、軟件架構
2.1、架構概述
圖1:切換到 AIDL 和 libbinder 后的 ServiceManager 類關系圖
圖注:
為了畫圖方便,將 namespace 寫成了下划線形式。
android_os_BpServiceManager 和 android_os_BnServiceManager、android_os_IServiceManager 類均在 android os 的 namespace 中,其他無下划線的類名,處於 android namespace 中。
一圖勝千言,11 之前的 SM 是寫在 c 文件里,沒有類的概念,現在基於 AIDL 和 libbinder,使用 CPP 語言,用 UML 就可以很形象地展示類關系了。就着這幅圖我們大致描述新的軟件架構。
- 紅色線段大概地將服務端與客戶端類相分隔,服務端在右下角。
一些 libbinder 的用於繼承的公共類請讀者自行剝離,而不是將其歸入某一端。例如 IBinder,我們知道他是 BBinder 和 BpBinder 的父類,是公共的接口約束。
- libbinder 中客戶端的入口變為:IServiceManager.cpp#ServiceManagerShim
之前無該輔助類,而是直接操作 BpServiceManager,這個輔助類封裝了 AIDL 自動生成的 BpServiceManager,所以現在的客戶端代碼流就變成如下三步:
1.用戶代碼
2.libbinder 代碼 binder/IServiceManager.cpp#ServiceManagerShim
3.AIDL 代碼 android/os/IServiceManager.cpp#BpServiceManager 接口
所以 libbinder 中的 ServiceManagerShim 起到了一個中轉的作用,把請求轉給 out 下 AIDL 自動生成的 BpServiceManager。
- BpServiceManager 的實現挪到 out
原來是在 libbinder#IServiceManager.cpp 中手寫實現,現在是 AIDL 幫你實現。
當然,該文件中同樣自動實現了 BnServiceManager類
代碼路徑
out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm64_armv8-a_shared/gen/aidl/android/os/IServiceManager.cpp
- 服務端的核心實現在 ServiceManager.cpp
原來是沒有 Bn 的,而是一個 binder_loop 方法溝通驅動,現在則是 ServiceManager 繼承了 BnServiceManager 來獲得代碼流。
- waitForService的改動:IServiceCallback.aidl
Waiter 類。新增了 Binder 匿名服務用來向 SM 注冊跨進程的回調,當 SM 檢測到有服務注冊時,會返回通知。
- 服務的客戶端數量監聽:IServiceCallback.aidl
IServiceCallback.aidl 這個匿名 Binder 服務就是用於該目的,可以監聽某個服務的客戶端數量。
2.2、文件路徑
- AIDL
AIDL 是一種方便的接口定義語言,用於 Binder-IPC 編程。詳細介紹與使用可參考:AIDL Overview
我們關注三個 AIDL,分別是 IServiceManager.aidl、IServiceCallback.aidl、IClientCallback.aidl,對應的編譯后生成的文件路徑為:
out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/
IClientCallback.cpp
IServiceCallback.cpp
IServiceManager.cpp
- libbinder 中的代碼路徑
frameworks/native/libs/binder/IServiceManager.cpp
- SM 服務端代碼路徑
frameworks/native/cmds/servicemanager/
main.cpp
Access.cpp
ServiceManager.cpp
本小節僅展示涉及變遷的文件路徑。簡潔起見只寫了 CPP 文件,對應的h頭文件可以附近查找。
另外需要特別區分的是,有兩個 IServiceManager 。
一個在 libbinder 中,是 android 的 name space,直接被用戶 #include<binder/IServiceManager>
使用。
另一個是aidl自動生成的 android os 的 name space,被上面的 libbinder 所使用 #include<android/os/IServiceManager>
。
2.3、小結
第二章節從全局的角度展示了 SM 切換到 AIDL 和 libbinder 的軟件架構,結合圖來看還是非常清楚易於理解的。
接下來跟蹤幾個情景流程,展示新架構中的細節。
三、servicemanager 啟動流程分析
圖2:servicemanager 啟動時序圖
如上圖,啟動流程的變動主要在進入循環的方式,Android 11 之前是通過 binder_loop
方法,而現在是通過 looper。下面展示細節。
frameworks/native/cmds/servicemanager/main.cpp
int main(int argc, char** argv) {
if (argc > 2) {
LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
}
const char* driver = argc == 2 ? argv[1] : "/dev/binder";
//溝通 Binder 驅動,open,mmap
sp<ProcessState> ps = ProcessState::initWithDriver(driver);
ps->setThreadPoolMaxThreadCount(0);
//oneway 限制,SM 發起的 Binder 調用必須是單向,否則打印堆棧日志提示
ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
//實例化 ServiceManager,傳入 Access 類用於鑒權
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";
}
//設置全局變量給 IPCThreadState
IPCThreadState::self()->setTheContextObject(manager);
//注冊到驅動,成為 Binder 管理員,handle 是 0
ps->becomeContextManager();
//准備 looper
sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
//通知驅動 BC_ENTER_LOOPER ,監聽驅動 fd ,有消息時回調到 handleEvent 處理 binder 調用
BinderCallback::setupTo(looper);
//服務的注冊監聽相關
ClientCallbackCallback::setupTo(looper, manager);
//無限循環等消息
while(true) {
looper->pollAll(-1);
}
// should not be reached
return EXIT_FAILURE;
}
和原來的 servicemanager 服務相比較,使用了 libbinder 后,代碼更規范化,和其他 Native 的服務風格趨於一致。
-
之前是直接 open、mmap 現在是借助 libbinder
-
之前是 binder_loop 死循環接收驅動的消息,現在是通過 looper 監聽 fd 來 handleEvent
-
之前的鑒權現在被獨立到單獨文件 Access.cpp
突然想起一個題目,servicemanager 映射的虛擬內存有多大?現在的答案是和普通應用一樣大:1 M - 2 頁。
frameworks/native/libs/binder/ProcessState.cpp
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
啟動流程比較清晰不多贅述,下一小節看 addService 的流程。
四、addService 流程分析
圖3:defaultServiceManager 流程
圖4:addService 客戶端流程
圖5:addService 服務端流程
先上圖,總覽 Native 的代碼流程,客戶端是 libbinder 里的 IServiceManager.cpp,服務端是我們的 ServiceManager.cpp
4.1、ServiceManagerShim::addService
frameworks/native/libs/binder/IServiceManager.cpp
status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated, int dumpsysPriority)
{
Status status = mTheRealServiceManager->addService(
String8(name).c_str(), service, allowIsolated, dumpsysPriority);
return status.exceptionCode();
}
直接使用的 mTheRealServiceManager,澄清疑問,mTheRealServiceManager 是誰?
4.1.1、mTheRealServiceManager 是誰?
frameworks/native/libs/binder/IServiceManager.cpp
#include <android/os/IServiceManager.h>
using AidlServiceManager = android::os::IServiceManager;
class ServiceManagerShim : public IServiceManager
{
protected:
sp<AidlServiceManager> mTheRealServiceManager;
......
ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl)
: mTheRealServiceManager(impl)
{}
可以看到,mTheRealServiceManager 就是一個 android::os::IServiceManager 類型的實例,並且在 ServiceManagerShim 實例化時賦值。
那么 ServiceManagerShim 何時實例化呢?答案是 defaultServiceManager() 中
frameworks/native/libs/binder/IServiceManager.cpp
sp<IServiceManager> defaultServiceManager()
{
std::call_once(gSmOnce, []() {
sp<AidlServiceManager> sm = nullptr;
while (sm == nullptr) {
//1、拿到 AidlServiceManager 類型的 BpServiceManager(new BpBinder(0)) 實例
sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
if (sm == nullptr) {
ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str());
sleep(1);
}
}
//2、new ServiceManagerShim
gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
});
return gDefaultServiceManager;
}
如注釋 1、2,mTheRealServiceManager 就是在這樣流程中賦值的。他的真是面目是 BpServiceManager(new BpBinder(0))
。
由圖1可知,我們拿到了操作 Binder 驅動的入口,BpServiceManager-->BpBinder-->IPCThreadState-->ioctl
關於一部分舊知識會貼拓展鏈接本文不做展開。interface_cast 的實現可參考:淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
好現在返回上節,直接走入 BpServiceManager#addService 方法
4.2、BpServiceManager::addService
out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IServiceManager.cpp
namespace android {
namespace os {
BpServiceManager::BpServiceManager(const ::android::sp<::android::IBinder>& _aidl_impl)
: BpInterface<IServiceManager>(_aidl_impl){//_aidl_impl 就是 BpBinder(0) 實例
}
--------------------------------------------------
::android::binder::Status BpServiceManager::addService(const ::std::string& name, const ::android::sp<::android::IBinder>& service, bool allowIsolated, int32_t dumpPriority) {
::android::Parcel _aidl_data;
_aidl_data.markForBinder(remoteStrong());//0、和 Rpc Binder有關
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
//1、寫 interface
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//2、寫 name
_aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//3、寫 binder 對象
_aidl_ret_status = _aidl_data.writeStrongBinder(service);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//4、寫 allowIsolated
_aidl_ret_status = _aidl_data.writeBool(allowIsolated);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//5、寫 dumpPriority
_aidl_ret_status = _aidl_data.writeInt32(dumpPriority);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//6、借助 BpBinder(0)#transact 來發起 Binder 通信
_aidl_ret_status = remote()->transact(BnServiceManager::TRANSACTION_addService, _aidl_data, &_aidl_reply, 0);
if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IServiceManager::getDefaultImpl())) {
return IServiceManager::getDefaultImpl()->addService(name, service, allowIsolated, dumpPriority);
}
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
//7、如果有返回值就從這個 parcel 包里讀
_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
goto _aidl_error;
}
if (!_aidl_status.isOk()) {
return _aidl_status;
}
_aidl_error:
_aidl_status.setFromStatusT(_aidl_ret_status);
return _aidl_status;
}
把 Android 10 的貼上來,我們對比看看
frameworks/native/libs/binder/IServiceManager.cpp
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated, int dumpsysPriority) {
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
data.writeInt32(dumpsysPriority);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
和 Android 11 之前手寫的 BpServiceManager 相比,本質是沒變的,就是多了些花里胡哨的規范性代碼。
到這里,客戶端的代碼就大致展示完了,transact 再往后就是舊有的流程,可參考:淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
之后走到 Binder 驅動,驅動又根據 handle == 0 找到對端,我們的 SM 進程,喚醒他開始處理請求。
4.3、BinderCallback::handleEvent
如圖 4:addService 服務端流程,現在開始服務端的流程展示。
frameworks/native/cmds/servicemanager/main.cpp
class BinderCallback : public LooperCallback {
public:
......
int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
IPCThreadState::self()->handlePolledCommands();
return 1; // Continue receiving callbacks.
}
};
之后走到 BR_TRANSACTION
frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::executeCommand(int32_t cmd)
{
switch ((uint32_t)cmd) {
case BR_TRANSACTION:
{
if (tr.target.ptr) {
//因為目的端 SM 所以 tr.target.ptr 為 0
}else {//開始業務分發
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
the_context_object 是 SM 啟動的時候設置好的
sp<BBinder> the_context_object;
void IPCThreadState::setTheContextObject(const sp<BBinder>& obj)
{
the_context_object = obj;
}
是 ServiceManager 類實例,所以也是一個 BBinder 對象,所以就有了 transact()-->onTransact() 的處理能力。
所以現在 the_context_object->transact()
調用就走到 BBinder 的 transact 又走到 BnServiceManager 的 onTransact() 方法,回到了這個 AIDL 自動生成的 IServiceManager.cpp 文件里。
兜兜轉轉還是在這個文件。
out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IServiceManager.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_addService:
{
::std::string in_name;
::android::sp<::android::IBinder> in_service;
bool in_allowIsolated;
int32_t in_dumpPriority;
//檢查 interface
if (!(_aidl_data.checkInterface(this))) {
_aidl_ret_status = ::android::BAD_TYPE;
break;
}
//讀 name
_aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
//讀 binder
_aidl_ret_status = _aidl_data.readStrongBinder(&in_service);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
//讀 in_allowIsolated
_aidl_ret_status = _aidl_data.readBool(&in_allowIsolated);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
//讀 in_dumpPriority
_aidl_ret_status = _aidl_data.readInt32(&in_dumpPriority);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
//調用真正的 ServiceManager.cpp 中的實現
::android::binder::Status _aidl_status(addService(in_name, in_service, in_allowIsolated, in_dumpPriority));
//如果有返回寫返回到 _aidl_reply
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK))) {
break;
}
if (!_aidl_status.isOk()) {
break;
}
}
和 Bp 端是對稱的操作,下一步走到 ServiceManager.cpp::addService 方法
4.4、ServiceManager::addService
frameworks/native/cmds/servicemanager/ServiceManager.cpp
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
auto ctx = mAccess->getCallingContext();
// uid 鑒權
if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
return Status::fromExceptionCode(Status::EX_SECURITY);
}
// selinux 鑒權
if (!mAccess->canAdd(ctx, name)) {
return Status::fromExceptionCode(Status::EX_SECURITY);
}
if (binder == nullptr) {
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
//檢查 name 命名
if (!isValidServiceName(name)) {
LOG(ERROR) << "Invalid service name: " << name;
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
//如果 vndservicemanager 則檢查 VINTF manifest
#ifndef VENDORSERVICEMANAGER
if (!meetsDeclarationRequirements(binder, name)) {
// already logged
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
#endif // !VENDORSERVICEMANAGER
//和 RPC Binder 有關,死亡監聽
// implicitly unlinked when the binder is removed
if (binder->remoteBinder() != nullptr &&
binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
LOG(ERROR) << "Could not linkToDeath when adding " << name;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
//新增一個結構體到 map 中
// Overwrite the old service if it exists
mNameToService[name] = Service {
.binder = binder,
.allowIsolated = allowIsolated,
.dumpPriority = dumpPriority,
.debugPid = ctx.debugPid,
};
//架構中提到的 waiteForService 的跨進程
auto it = mNameToRegistrationCallback.find(name);
if (it != mNameToRegistrationCallback.end()) {
for (const sp<IServiceCallback>& cb : it->second) {
mNameToService[name].guaranteeClient = true;
// permission checked in registerForNotifications
cb->onRegistration(name, binder);
}
}
return Status::ok();
}
五、其他值得關注的細節
前兩節是全局總覽、經典情景的視角看代碼,現在我們換一個視角,展示一些邊邊角角的內容為上面的主干填充細節。
5.1、servicemanager 的能力變化
11之前僅有4個接口暴露給應用
frameworks/native/libs/binder/include/binder/IServiceManager.h
enum {
GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION,
};
而 Android 11 增加到 9 個,Android 12 又增加到 13 個
out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/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_getConnectionInfo = ::android::IBinder::FIRST_CALL_TRANSACTION + 9;
static constexpr uint32_t TRANSACTION_registerClientCallback = ::android::IBinder::FIRST_CALL_TRANSACTION + 10;
static constexpr uint32_t TRANSACTION_tryUnregisterService = ::android::IBinder::FIRST_CALL_TRANSACTION + 11;
static constexpr uint32_t TRANSACTION_getServiceDebugInfo = ::android::IBinder::FIRST_CALL_TRANSACTION + 12;
從這些接口的變動我們也可以很清晰地把握住 servicemanager 的前進方向
5.2、DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE
frameworks/native/libs/binder/include/binder/IInterface.h
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
static_assert(internal::allowedManualInterface(NAME), \
"b/64223827: Manually written binder interfaces are " \
"considered error prone and frequently have bugs. " \
"The preferred way to add interfaces is to define " \
"an .aidl file to auto-generate the interface. If " \
"an interface must be manually written, add its " \
"name to the whitelist."); \
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
-----------------------------
constexpr const char* const kManualInterfaces[] = {
"android.app.IActivityManager",
"android.app.IUidObserver",
"android.drm.IDrm",
"android.dvr.IVsyncCallback",
"android.dvr.IVsyncService",
"android.gfx.tests.ICallback",
"android.gfx.tests.IIPCTest",
......
以后手寫的 Native 服務需要關注下這個宏,做了限制。谷歌建議是現在的 Native 服務都用 AIDL,別手寫。
5.3、String16、String8 與 name
AIDL 改造之前,都是一路 String16 從客戶端傳到服務端,而現在需要繞一些路了。還是以 addService 為例
status_t ServiceManagerShim::addService(const String16& name,){
Status status = mTheRealServiceManager->addService(
String8(name).c_str(), );
在這里轉一次,16 轉成 8
------------------------------------------
_aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
在 BpServiceManager 里又轉了一次,8 轉 16
------------------------------------------
_aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
現在來到 BnServiceManager 繼續轉,16 轉 8
轉來轉去快暈了。總結就是,SM 服務端都是操作的 utf8,而 libbinder 客戶端都是 utf16。有修改的話需要注意下編碼問題。
也可能是由於這個轉換問題,在服務端加了個服務名檢查
bool isValidServiceName(const std::string& name) {
if (name.size() == 0) return false;
if (name.size() > 127) return false;
for (char c : name) {
if (c == '_' || c == '-' || c == '.' || c == '/') continue;
if (c >= 'a' && c <= 'z') continue;
if (c >= 'A' && c <= 'Z') continue;
if (c >= '0' && c <= '9') continue;
return false;
}
return true;
}
5.4、服務保存的數據結構
SM 需要保存服務及其對應的信息,11 前用的鏈表 svc_list,成員是 svc_info 結構體;11 后用的 map,成員是結構體 Service。
frameworks/native/cmds/servicemanager/ServiceManager.h
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;
這個 Service 結構體有了更多的信息和能力,getNodeStrongRefCount() 方法可以獲取該服務有多少個客戶端。
5.5、listServices 返回值
11 之前的實現是客戶端循環 checkService,11 之后是直接返回的是 std::vector
- 客戶端
frameworks/native/libs/binder/IServiceManager.cpp
Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority)
{
std::vector<std::string> ret;
if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
return {};
}
Vector<String16> res;
res.setCapacity(ret.size());
for (const std::string& name : ret) {
res.push(String16(name.c_str()));
}
return res;
}
- 服務端
frameworks/native/cmds/servicemanager/ServiceManager.cpp
Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::string>* outList) {
size_t toReserve = 0;
for (auto const& [name, service] : mNameToService) {
(void) name;
if (service.dumpPriority & dumpPriority) ++toReserve;
}
outList->reserve(toReserve);
for (auto const& [name, service] : mNameToService) {
(void) service;
if (service.dumpPriority & dumpPriority) {
outList->push_back(name);
}
}
這里也可以看到字符編碼的問題,客戶端用的是 utf16,而服務端用的是 utf8
- 順便提一嘴 dumpsys 的畫蛇添足的修改
frameworks/native/cmds/dumpsys/dumpsys.cpp
if (services.empty() || showListOnly) {
services = listServices(priorityFlags, asProto);
......
if (N > 1) {
for (size_t i=0; i<N; i++) {
sp<IBinder> service = sm_->checkService(services[i]);
獲取到服務列表后為什么再循環 check 一遍呢?我感覺是沒有必要的。
5.6、waitForService 與 IServiceCallback.aidl
利用了匿名 Binder 來傳遞回調,有興趣可以自己看看。
- 回調注冊
frameworks/native/libs/binder/IServiceManager.cpp
sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
{
class Waiter : public android::os::BnServiceCallback {
Status onRegistration(const std::string& /*name*/,
const sp<IBinder>& binder) override {
......
sp<Waiter> waiter = sp<Waiter>::make();
if (Status status = mTheRealServiceManager->registerForNotifications(name, waiter);
- 回調響應
frameworks/native/cmds/servicemanager/ServiceManager.cpp
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
auto it = mNameToRegistrationCallback.find(name);
if (it != mNameToRegistrationCallback.end()) {
for (const sp<IServiceCallback>& cb : it->second) {
mNameToService[name].guaranteeClient = true;
// permission checked in registerForNotifications
cb->onRegistration(name, binder);
}
}
- AIDL 及其生成的代碼位置
frameworks/native/libs/binder/aidl/android/os/IServiceCallback.aidl
out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IServiceCallback.cpp
5.7、IClientCallback.aidl
IServiceManager.aidl 中定義的接口,都是在 #include <binder/IServiceManager.h>
嗎?答案為否。IClientCallback 就是這樣一個例子。
想用 registerClientCallback 方法注冊回調,需要直接使用 #include <android/os/IServiceManager.h>
拿到 BpServiceManager 實例,來通信。
這個接口沒有暴露在 libbinder 的 IServiceManager 中。
這個回調用於監聽某個服務有 client,和 IServiceCallback.aidl 一樣是匿名 binder 服務,一個例子 LazyServiceRegistrar.cpp,可自行了解。
代碼路徑
frameworks/native/libs/binder/aidl/android/os/IClientCallback.aidl
frameworks/native/libs/binder/LazyServiceRegistrar.cpp
out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IClientCallback.cpp
frameworks/native/cmds/servicemanager/ServiceManager.cpp
5.8、RPC-Binder
Minimal-ish change for basic binder RPC.
This enables binder to work over sockets. The main change to core code
is in 'Parcel' and 'BpBinder'. The Parcel format is now associated with
the binder that it is either for or a reply from (we no longer have
binder 'objects' for the kernel). BpBinder is extended to support
talking over sockets (ideally, this would be a subclass, but
IBinder::localBinder/remoteBinder mean there is a lot of code which
presupposes what type of binder we have).
In addition, we have a few new objects:
- RpcServer - set this up to serve a connection
- RpcConnection - symmetrical object handling dispatch to a known
server/client
- RpcAddress - (this will definitely change) randomly generated
addresses - this might include things like host VM context, ip
address, or similar in the future. In that case, the address
generation should be cryptographically secure.
- RpcState - this keeps track of known binders, their refcounts, and
async transactions, and it understand the binder socket wire
protocol
The connection itself looks like N socket accepts to a server (the
server might have M socket accepts back to the client for symmetrical
connections, that is connections which need more than nested
transactions). The number of these socket connections controls how many
synchronous transactions can be made. Wherever possible, the behavior
here seeks to mimick the binder driver, and some differences are
documented in the code.
After this CL merges, the future work I intend on completing includes:
- support to work over vsock
- performance benchmarking
- optimization of the socket code here (may include delaying refcounts)
- support to pass 'transitive' binders (pass a binder from one service
to a different service, to let it setup a new connection). This task
may be excluded from my efforts as a security hedge if I can manage.
- fuzzer for this wire format
- support for linkToDeath
- support for transaction encryption
- support for promoting from a weak pointer
- handling SIGPIPE for dead connections
- and many more! :)
Bug: 167966510
Test: binderRpcTest
Change-Id: I276c6e312f584b57f4e7a14389ea4a1d63cfa2f4
smoreland@google.com(作者)
提交日期 3月24日 AM9:53
可能是受了蘋果和鴻蒙的刺激,谷歌也咔咔弄上了萬物互聯、分布式。這個提交大意是將 Binder 通信拓展支持跨設備,后面有機會再研究。
六、總結和參考資料
SM 經過 Aidl 和 libbinder 改造后,對於開發者來說,修改會更加規范和省心
新引入的特性展示了 SM 功能更多的可能性,可為特定需求提供思路,Native AIDL 和匿名 Binder 回調值得學習。
關於 AIDL 的使用可以參照官方文檔:
Android 11 之前的 Native Binder 可以參考老羅的書或者博客:
Android進程間通信(IPC)機制Binder簡要介紹和學習計划
淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路
淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路