我一直覺得,現代計算機不是一門科學,起碼快算不上一門理科科學。上上下下全是人造,左左右右全是生意,用管理學,經濟學去學計算機,也許更看得懂很多問題。HAL就是一個典型例子。
傳統Linux繞開了微軟的霸權,但是又面臨GPL要開源的尷尬。谷歌為了迎合硬件資本家封閉壟斷發財的愿望,所以搞了HAL這個概念。將原來在內核態的驅動,移了大部分核心內容到用戶態,這樣就可以封閉,可以壟斷賺錢。然后因為HAL這玩意只在安卓上有,配合了安卓的硬件公司反過來又被谷歌綁架,這樣一環套一環吃錢。一開始用Java,吸引廣大的Java生態碼農進場。現在又搞Kotlin想把碼農套牢。搞這幾出,是真的只是科學嗎?當然不是,歸根結底大部分還是生意。
我對安卓接觸不久,有些理解不一定對,大家用批判的眼光看就好。有什么錯誤還請指正。
一 安卓硬件接口的演化
傳統Linux怎么調用硬件?就是ko。。。幾個函數搞定。Android復雜了很多,所以整理一下。
在安卓中,除了上面講的HAL,還有一個就是Framework,這個就是app的framework,要理解安卓驅動層,這兩點繞不開。為了適配framework,安卓把硬件是作為服務service來使用。在Android中,這種結構也進化了很多代。
1 首先是傳統HAL(Legacy HAL)
在內核8.0以前使用。用戶態的so貌似保存在/system/lib64,這個版本是直接讀取硬件so,比較原始暴力。
App->Service->AIDL->Server->JNI->HAL so->kernel driver
2 現代HAL(Conventional HAL)
使用Iibhardware來管理so,同時下層的驅動使用一個單獨的分區,so全部集成到vender.img,和system解綁。要找尋so通過libhardware這個中間層。編譯時要提供一個Android.bp文件。
App->Service->AIDL->Server->JNI->Iibhardware->so(vender.img)
3 HIDL
在安卓8之后,開始使用HIDL,總的來說就是將HAL封裝成服務,完全就是rpc的玩法。
HIDL編譯后,會生成Android.bp(這個有時間再看看)。最后會有兩個so,一個so,放在system分區;一個impl.so,放在vendor分區,以此實現framework和驅動服務的分離。客戶端使用前者,服務端使用后者。服務端包含impl.so之后,會生成一個可執行程序,就可以作為一個service單獨運行。客戶端包含了so可以直接調用服務。
分為直通式和綁定式。有大神說直通式就是雖然使用HAL,但還是在一個進程,綁定式是使用HAL,但是數據通過Binder轉發,上面說的應該就是綁定式。直通式和綁定式也都是HAL生成的代碼中控制的。比如:
extern "C" IXXX* HIDL_FETCH_IXXX(const char* name);
AIDL和HIDL的中間就是安卓的framework。
App->AIDL->Service->HIDL->HAL Service->so(vender.img)
4 全AIDL
(10內核開始)。
App->AIDL->HAL Service->so(vender.img)
來自ASOP官網的圖。
二 看一下AIDL和HIDL。
最新的HAL主要涉及到的主要是兩個接口,AIDL和HIDL。
首先是AIDL,Android Interface definition language。看資料說是android中兩個app交互的IPC方式。首先IPC有很多種,管道,域套接字,message,共享內存,問題是谷歌為什么要搞出來一套新的呢?
從一個AIDL的例子可以看到:
// IMyRemoteService.aidl
interface IMyRemoteService {int getValue();void setValue(int value);
}
一邊使用:
private final IMyRemoteService.Stub mBinder = new IMyRemoteService.Stub()
另一邊使用:
mRemoteService = IMyRemoteService.Stub.asInterface(iBinder);
在接口中主要定義的還是函數,也就是說比管道這些更上層,更適合Java的調用。就算上層函數調用,其實也很多方式,比如COM,soap,rpc都是干這事的。安卓應該還是用binder進行統一管理了吧,畢竟是一個單獨的服務。
HIDL
主要還是提供底層cpp驅動和上層java的通信。hal文件定義如下:
// ILedService.hal
package android.hardware.led;interface ILedService {int getLedState();void setLedState(int state);
};
它的C++語法稍怪:
#include <android/hardware/led/1.0/ILedService.h>
#include <hidl/LegacySupport.h>using android::hardware::led::V1_0::ILedService;
using android::hardware::Return;
using android::hardware::Void;class LedService : public ILedService {
public:LedService() {}Return<int32_t> getLedState() override {return mLedState;}//略
};int main() {return android::hardware::configureRpcThreadpool(1, true) == android::OK &&android::hardware::registerAsService(new LedService()) == android::OK? 0: 1;
}
Java側的倒是差不多。
在Binder的使用中,Server端繼承BnInterface, Client端繼承BpInterface。我接觸的工程中,一邊叫做BP側,那么應該就是app側,BN側那么就是服務端了。
最后,寫完的service可以通過rc文件,作為一個系統服務。
參考:
針對 Android 進行開發 ?|? Android 開發者 ?|? Android Developers
https://source.android.com/docs/core/architecture?hl=zh-cn
https://source.android.com/docs/core/architecture/aidl/aidl-hals?hl=zh-cn
AIDL for HALs實戰_hidl會被aidl代替-CSDN博客
Android HIDL 介紹學習和實戰應用-CSDN博客
AIDL for HALs實戰_hidl會被aidl代替-CSDN博客
HIDL 原理及使用詳解-CSDN博客
Android上層與驅動交互完整篇(三)HIDL服務_android.bp hidl_interface-CSDN博客
Android HIDL學習(2) ---- HelloWorld - 簡書