做Android底層開發(fā)的同學(xué),肯定繞不開“燈光控制”——手機(jī)屏幕背光、按鍵燈、呼吸燈,這些功能的底層實(shí)現(xiàn)都依賴Light HAL。今天就以Rockchip(瑞芯微)Android 15平臺(tái)為例,用最通俗的語(yǔ)言拆解Light HAL的核心邏輯,新手也能看懂!
一、先搞懂:什么是Light HAL?
在開始看代碼前,先理清3個(gè)核心概念,避免越看越懵:
1. HAL是什么?
HAL(硬件抽象層)是Android系統(tǒng)“Framework層”和“硬件驅(qū)動(dòng)”之間的橋梁。Framework層負(fù)責(zé)上層邏輯(比如APP調(diào)“調(diào)亮屏幕”),驅(qū)動(dòng)負(fù)責(zé)直接操作硬件,HAL則把驅(qū)動(dòng)接口封裝成標(biāo)準(zhǔn)形式,讓Framework不用關(guān)心不同廠商的硬件差異。
2. Light HAL的作用?
專門負(fù)責(zé)“燈光類硬件”的控制,比如:
?屏幕背光(BACKLIGHT)的亮度調(diào)節(jié);
?按鍵燈(BUTTONS)的開關(guān);
?通知燈(NOTIFICATIONS)的呼吸/常亮效果;
?電池?zé)簦?/span>BATTERY)的顏色/閃爍控制。
3. AIDL版HAL?
Android 10+后,HAL逐漸從舊的HIDL遷移到AIDL(Android接口定義語(yǔ)言),核心是用Binder通信,讓HAL服務(wù)以“進(jìn)程”形式運(yùn)行,更穩(wěn)定、權(quán)限控制更清晰。
二、核心代碼拆解:Rockchip Light HAL文件全解析
瑞芯微的Light HAL代碼都在light_aidl目錄下,核心文件就5個(gè),我們逐個(gè)講清楚作用:
1.頭文件:Lights.h(定義“骨架”)
// 關(guān)鍵代碼片段classBacklightPath{public:intphysic_id; // 顯示屏物理ID(多屏場(chǎng)景用)charbacklight_path[128];// 背光驅(qū)動(dòng)的sysfs路徑};classLights:publicBnLights {// Framework調(diào)用的核心接口:設(shè)置燈光狀態(tài)(比如調(diào)亮度)ndk::ScopedAStatussetLightState(intid,constHwLightState& state)override;// Framework調(diào)用的核心接口:獲取設(shè)備支持的燈光類型ndk::ScopedAStatusgetLights(std::vector* types) override;private:// 輔助函數(shù):添加支持的燈光類型(比如“背光”“按鍵燈”)voidaddLight(intconstordinal, LightTypeconsttype);// 存儲(chǔ)支持的燈光列表std::vector_lights; // 存儲(chǔ)多屏背光的路徑(瑞芯微多屏方案的核心)std::vector_backlights; };
新手理解:這個(gè)文件就像“設(shè)計(jì)圖”,定義了兩個(gè)核心:
?BacklightPath:解決多屏設(shè)備的背光路徑問題(比如平板/工控機(jī)有多個(gè)屏幕);
?Lights類:實(shí)現(xiàn)了Android標(biāo)準(zhǔn)的BnLights接口,對(duì)外暴露“設(shè)置燈光”和“獲取燈光”兩個(gè)核心方法,是整個(gè)HAL的骨架。
2.實(shí)現(xiàn)文件:Lights.cpp(填充“血肉”)
這是核心邏輯文件,所有燈光控制的實(shí)際操作都在這里,新手重點(diǎn)看3個(gè)核心函數(shù):
(1)getDriverPath:定義燈光的驅(qū)動(dòng)路徑
constchar*getDriverPath(LightType type){switch(type) {caseLightType:return"/sys/class/backlight/backlight/brightness";// 背光驅(qū)動(dòng)路徑caseLightType:return"/sys/class/leds/button-backlight/brightness";// 按鍵燈路徑// 通知燈/電池?zé)舻戎赶?a target="_blank">LED驅(qū)動(dòng)目錄caseLightType:caseLightType:return"/sys/class/leds";default:return"/not_supported";}}
新手理解:Android控制硬件的核心是操作sysfs(虛擬文件系統(tǒng)),比如想調(diào)背光,本質(zhì)就是往/sys/class/backlight/backlight/brightness文件里寫數(shù)字(0-255),這個(gè)函數(shù)就是給不同燈光“找對(duì)應(yīng)的文件路徑”。
(2)write_int:往驅(qū)動(dòng)文件寫值(操作硬件)
staticintwrite_int(constchar* path,intvalue){intfd =open(path, O_RDWR);// 打開驅(qū)動(dòng)文件if(fd >=0) {charbuf[20];snprintf(buf,sizeof(buf),"%dn", value);// 把亮度值轉(zhuǎn)成字符串write(fd, buf,strlen(buf));// 寫入文件(真正調(diào)亮度的操作)close(fd);return0;}else{ALOGE("打開文件失敗:%s",strerror(errno));return-errno;}}
新手理解:這是最底層的硬件操作函數(shù),比如Framework要求“把背光調(diào)到100”,最終就是這個(gè)函數(shù)往背光路徑里寫“100”,驅(qū)動(dòng)收到后就會(huì)調(diào)屏幕亮度。
(3)setLightState:處理Framework的調(diào)用請(qǐng)求
ndk::ScopedAStatusLights::setLightState(int id,constHwLightState& state) {// 1. 根據(jù)id找到對(duì)應(yīng)的燈光類型(比如是背光還是按鍵燈)// 2. 找到該燈光的驅(qū)動(dòng)路徑// 3. 調(diào)用setLightFromType,最終調(diào)用write_int寫值到驅(qū)動(dòng)// 4. 返回操作結(jié)果(成功/失敗)}
新手理解:Framework層調(diào)用Light HAL時(shí),直接調(diào)用這個(gè)函數(shù),它是“上層請(qǐng)求”和“底層操作”的中轉(zhuǎn)站。
3.入口文件:main.cpp(啟動(dòng)HAL服務(wù))
int main() {//1. 初始化Binder線程池(AIDL通信的基礎(chǔ))ABinderProcess_setThreadPoolMaxThreadCount(0);//2. 創(chuàng)建Lights實(shí)例(真正處理燈光邏輯的對(duì)象)std::shared_ptr<Lights> lights = ndk::SharedRefBase::make(); //3. 把HAL服務(wù)注冊(cè)到系統(tǒng)的ServiceManager(Framework能找到這個(gè)服務(wù))const std::string instance = std::string() +Lights::descriptor+"/default";AServiceManager_addService(lights->asBinder().get(), instance.c_str());//4. 進(jìn)入線程池,等待Framework的調(diào)用(常駐進(jìn)程)ABinderProcess_joinThreadPool();returnEXIT_FAILURE;}
新手理解:這個(gè)文件是HAL服務(wù)的“啟動(dòng)入口”,就像你開餐館,main.cpp就是“開門營(yíng)業(yè)”的操作:
?初始化通信(Binder線程池);
?準(zhǔn)備好廚師(Lights實(shí)例);
?告訴顧客(Framework)“我在這營(yíng)業(yè)”(注冊(cè)服務(wù));
?坐等顧客下單(等待Framework調(diào)用)。
4.配置文件:lights-rockchip.xml(聲明HAL服務(wù))
<manifestversion="1.0"type="device"><halformat="aidl"><name>android.hardware.lightname><version>2version><fqname>ILights/defaultfqname>hal>manifest>
新手理解:這個(gè)文件是“給系統(tǒng)看的說(shuō)明書”,告訴Android系統(tǒng):“我是Light HAL服務(wù),版本是2,接口名是ILights/default”,系統(tǒng)會(huì)通過(guò)這個(gè)文件校驗(yàn)HAL的兼容性,確保Framework能正確調(diào)用。
5.啟動(dòng)配置:lights-rockchip.rc(系統(tǒng)啟動(dòng)HAL)
service vendor.light-rockchip/vendor/bin/hw/android.hardware.lights-service.rockchipclass halusersystemgroupsystemshutdown critical
新手理解:Android開機(jī)后,init進(jìn)程會(huì)掃描這個(gè)文件,然后自動(dòng)啟動(dòng)Light HAL服務(wù):
?class hal:屬于HAL類服務(wù),系統(tǒng)啟動(dòng)時(shí)會(huì)批量啟動(dòng);
?user system:以system用戶運(yùn)行(保證能讀寫驅(qū)動(dòng)文件);
?shutdown critical:關(guān)鍵服務(wù),崩潰會(huì)重啟,關(guān)機(jī)要等它退出。
Light HAL服務(wù)完整啟動(dòng)流程圖
用流程圖直觀展示系統(tǒng)開機(jī)后,HAL服務(wù)如何啟動(dòng),一看就懂:

三、整體運(yùn)行流程:從“調(diào)亮度”到“硬件響應(yīng)”
新手最容易懵的是“代碼怎么串起來(lái)的”,用“調(diào)屏幕亮度”舉例子,先看流程圖,再看步驟:

對(duì)應(yīng)流程圖,完整流程拆解(7步):
1.系統(tǒng)開機(jī):init進(jìn)程掃描lights-rockchip.rc,啟動(dòng)android.hardware.lights-service.rockchip可執(zhí)行文件;
2.啟動(dòng)HAL服務(wù):執(zhí)行main.cpp,創(chuàng)建Lights實(shí)例,注冊(cè)服務(wù)到ServiceManager,等待調(diào)用;
3.上層發(fā)起請(qǐng)求:比如設(shè)置里調(diào)亮度,Framework層找到“ILights/default”服務(wù),調(diào)用setLightState;
4.HAL處理請(qǐng)求:setLightState根據(jù)燈光id找到背光驅(qū)動(dòng)路徑;
5.底層操作:調(diào)用write_int往/sys/class/backlight/backlight/brightness寫亮度值;
6.驅(qū)動(dòng)響應(yīng):內(nèi)核驅(qū)動(dòng)收到文件寫入操作,控制屏幕背光硬件調(diào)亮度;
7.返回結(jié)果:HAL把操作結(jié)果返回給Framework,整個(gè)流程結(jié)束。
四、避坑指南
1.路徑錯(cuò)誤:驅(qū)動(dòng)路徑寫錯(cuò)(比如多屏場(chǎng)景背光路徑不對(duì)),會(huì)導(dǎo)致“調(diào)亮度沒反應(yīng)”,重點(diǎn)查getDriverPath和display_settings.xml;
2.權(quán)限問題:HAL服務(wù)運(yùn)行用戶不是system,會(huì)導(dǎo)致打不開驅(qū)動(dòng)文件,查lights-rockchip.rc的user/group;
3.接口兼容:lights-rockchip.xml的版本和接口名不對(duì),Framework找不到服務(wù),重點(diǎn)核對(duì)name/version/fqname;
4.多屏場(chǎng)景:瑞芯微多屏設(shè)備要注意BacklightPath的物理ID,否則只會(huì)調(diào)其中一個(gè)屏幕。
五、總結(jié)
Rockchip Light HAL的核心邏輯其實(shí)很簡(jiǎn)單:
?用Lights.h定義接口骨架;
?用Lights.cpp實(shí)現(xiàn)硬件操作邏輯;
?用main.cpp啟動(dòng)并注冊(cè)HAL服務(wù);
?用rc/xml配置服務(wù)啟動(dòng)和系統(tǒng)識(shí)別;
?本質(zhì)是“把Framework的請(qǐng)求轉(zhuǎn)成往sysfs文件寫值”。
對(duì)新手來(lái)說(shuō),先搞懂“sysfs操作硬件”這個(gè)核心,再順著“Framework→HAL→驅(qū)動(dòng)”的鏈路看代碼,就不會(huì)亂。建議先改改背光路徑、調(diào)個(gè)亮度值,動(dòng)手比只看代碼更易理解!
-
Android
+關(guān)注
關(guān)注
12文章
4033瀏覽量
134202 -
Linux
+關(guān)注
關(guān)注
88文章
11782瀏覽量
219244 -
Rockchip
+關(guān)注
關(guān)注
0文章
92瀏覽量
19620
發(fā)布評(píng)論請(qǐng)先 登錄
rk3576 android15平臺(tái)camera編譯配置都做了什么?
RK3576 Android15音頻開發(fā)必看:alsa_route核心文件解析與修改場(chǎng)景
RK3576平臺(tái)Android HAL層故障排查:從lshal命令看透問題本質(zhì)
硬核進(jìn)階:RK3576 Android15?驅(qū)動(dòng)與系統(tǒng)開發(fā)實(shí)戰(zhàn)指南
深入解析rk平臺(tái)Android Bootloader核心代碼:從啟動(dòng)流程到AVB驗(yàn)證
新手必看!華潤(rùn)微7388全系統(tǒng)改裝零失敗復(fù)盤,這些坑我替你踩過(guò)了
【RK3568 NPU實(shí)戰(zhàn)】別再閑置你的NPU!手把手帶你用迅為資料跑通Android AI檢測(cè)Demo,附完整流程與效果
實(shí)戰(zhàn)RK3568性能調(diào)優(yōu):如何利用迅為資料壓榨NPU潛能-在Android系統(tǒng)中使用NPU
新手必看!Android Light HAL開發(fā)實(shí)戰(zhàn)(Rockchip 15 AIDL版)
評(píng)論