1. 程式人生 > >AndroidO Treble架構下的變化

AndroidO Treble架構下的變化

AndroidO引入Treble架構後,有那些變化呢?

1. 增加了多個服務管家,AndroidO之前版本有且只有一個servicemanager,現在增加到3個,他們分管不同的服務。
2. 增加了binder通訊庫,這是為了適配binder域的擴充套件。
3. 增加了binder域,系統定義了3個binder裝置節點,binder驅動分別處理這3個binder裝置節點上的binder通訊事件。

Binder通訊域變化

Treble架構的引入足以說明Binder通訊的重要性,之前APP和Framework之間通過binder實現跨程序呼叫,當然這個呼叫對開發者來說是透明的,相當於函式本地呼叫。Treble引入後,Framework和HAL又實現了程序分離,Framework和HAL之間依然使用binder通訊,通過HIDL來定義通訊介面。那binder通訊有什麼變化呢? 在Treble中,引入了多個binder域,主要是增加了多個binder裝置,binder驅動實現原理基本沒變,變化了一些細節。增加binder裝置應該是為了實現更換的許可權控制,使用不同binder裝置的主體和客體之間的selinux許可權有所不同,同時,Android 框架和 HAL 現在使用 Binder 互相通訊。由於這種通訊方式極大地增加了 Binder 流量。
為了明確地拆分框架(與裝置無關)和供應商(與具體裝置相關)程式碼之間的 Binder 流量,Android O 引入了“Binder 上下文”這一概念。每個 Binder 上下文都有自己的裝置節點和上下文(服務)管理器。您只能通過上下文管理器所屬的裝置節點對其進行訪問,並且在通過特定上下文傳遞 Binder 節點時,只能由另一個程序從相同的上下文訪問上下文管理器,從而確保這些域完全互相隔離。為了顯示 /dev/vndbinder,請確保核心配置項 CONFIG_ANDROID_BINDER_DEVICES 設為”binder,hwbinder,vndbinder”

static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; 

module_param_named(devices, binder_devices_param, charp, S_IRUGO);

以kernel引數形式得到配置的binder裝置節點名稱,然後在binder驅動中建立不同的binder裝置:

static int __init binder_init(void)  
{  
    int ret;  
    char *device_name, *device_names;  
    struct
binder_device *device; struct hlist_node *tmp; ... /* * Copy the module_parameter string, because we don't want to * tokenize it in-place. */ device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL); if (!device_names) { ret = -ENOMEM; goto
err_alloc_device_names_failed; } strcpy(device_names, binder_devices_param); while ((device_name = strsep(&device_names, ","))) { ret = init_binder_device(device_name); if (ret) goto err_init_binder_device_failed; } return ret; err_init_binder_device_failed: hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) { misc_deregister(&device->miscdev); hlist_del(&device->hlist); kfree(device); } err_alloc_device_names_failed: debugfs_remove_recursive(binder_debugfs_dir_entry_root); return ret; }
static int __init init_binder_device(const char *name)  
{  
    int ret;  
    struct binder_device *binder_device;  

    binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);  
    if (!binder_device)  
        return -ENOMEM;  

    binder_device->miscdev.fops = &binder_fops;  
    binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;  
    binder_device->miscdev.name = name;  

    binder_device->context.binder_context_mgr_uid = INVALID_UID;  
    binder_device->context.name = name;  
    mutex_init(&binder_device->context.context_mgr_node_lock);  

    ret = misc_register(&binder_device->miscdev);  
    if (ret < 0) {  
        kfree(binder_device);  
        return ret;  
    }  

    hlist_add_head(&binder_device->hlist, &binder_devices);  

    return ret;  
}  

這樣在驅動中就建立了binder、vndbinder、hwbinder三個驅動裝置,並儲存在binder裝置列表binder_devices中。/dev/binder 裝置節點成為了框架程序的專屬節點,這意味著oem程序將無法再訪問該節點。oem程序可以訪問 /dev/hwbinder,但必須將其 AIDL 介面轉為使用 HIDL。

binder驅動裝置

hwbinder驅動裝置

vndbinder驅動裝置


由於vndbinder和binder使用的都是libbinder.so庫,因此在開啟binder裝置時,需要呼叫:
ProcessState::initWithDriver(“/dev/vndbinder”);來指定開啟那個binder裝置。

服務管家變化

AndroidO將服務管家從servicemanager擴充套件到以下3個:

servicemanager

原始碼:

編譯指令碼:
這裡寫圖片描述

vndservicemanager

以前Binder 服務通過 servicemanager 註冊,其他程序可從中檢索這些服務。在 Android O 中,servicemanager 現在專用於框架和應用程序,供應商程序無法再對其進行訪問。不過,供應商服務現在可以使用 vndservicemanager,這是一個使用 /dev/vndbinder而非 /dev/binder 的 servicemanager 的新例項。供應商程序無需更改即可與vndservicemanager 通訊;當供應商程序開啟 /dev/vndbinder 時,服務查詢會自動轉至 vndservicemanager。servicemanager和vndservicemanager使用的是同一份程式碼,都是由service_manager.c編譯而來。
這裡寫圖片描述
在啟動servicemanager 時,並沒有傳參,而啟動vndservicemanager時,傳遞了binder裝置節點。

這裡寫圖片描述
vndservicemanager使用/dev/vndbinder驅動裝置,而servicemanager使用/dev/binder驅動裝置。在編譯vndservicemanager時指定了VENDORSERVICEMANAGER巨集:

cflags: [  

       "-DVENDORSERVICEMANAGER=1",  

    ],  

這裡寫圖片描述

vndservicemanager與servicemanager不僅使用的binder裝置不同,使用的selinux策略也不同。

vndservicemanager使用的selinux策略檔案為:”/vendor/etc/selinux/vndservice_contexts”

servicemanager使用的selinux策略檔案為:”/system/etc/selinux/plat_service_contexts”

1) servicemanager和vndservicemanager使用的binder裝置節點不同:

servicemanager使用/dev/binder

vndservicemanager使用/deve/vndbinder

2) servicemanager和vndservicemanager使用的selinux策略檔案不同:

servicemanager使用/system/etc/selinux/plat_service_contexts

 vndservicemanager使用/vendor/etc/selinux/vndservice_contexts

3) 檢視servicemanager和vndservicemanager管理的binder服務的工具不同:

servicemanager使用service list

vndservicemanager使用vndservice list

hwservicemanager

這裡寫圖片描述

這裡寫圖片描述

該hwservicemanager用於管理hidl服務,因此其實現和servicemanager完全不同,使用的binder庫也完全不同。

Binder庫變化

servicemanager和vndservicemanager都使用libbinder庫,只是他們使用的binder驅動不同而已,而hwservicemanager使用libhwbinder庫,binder驅動也不同。

libbinder庫原始碼:

這裡寫圖片描述

libhwbinder庫原始碼:

這裡寫圖片描述

檔案對比:

這裡寫圖片描述

Binder通訊框架變化

這裡寫圖片描述

1.在普通Java Binder框架中,Client端Proxy類完成資料打包,然後交給mRemotebinder代理來完成資料傳輸。Server端Stub類完成資料解析,然後交給其子類實現。

2.在普通Native Binder框架中,Client端BpXXX類完成資料打包,然後交給mRemoteBpBinder來完成資料傳輸。Server端BnXXX類完成資料解析,然後交個其子類實現。

  1. 在HwBinder框架中,Client端的BpHwXXX類完成資料打包,然後交給mRemoteBpHwBinder來完成資料傳輸。Server端的BnHwXXX類完成資料解析,然後交給_hidl_mImpl來實現。

框架層Binder物件變化

這裡寫圖片描述

這裡寫圖片描述