init.usb.rc的作用是在Android系統啟動和運行時,通過監聽屬性(sys.usb.config和sys.usb.configfs, sys.usb.typec.mode)變化動態,通過寫入內核接口 /sys/class/android_usb/ 來配置USB模式。
1 USB子系統的啟動
1.1 on init階段的配置
在on init階段設置sys.usb.configfs屬性,該屬性時USB配置方式開關,用來選擇使用哪種內核機制來配置USB,0-表示傳統模式,1-表示現代configfs模式。
on initsetprop sys.usb.configfs 0
? 兩種模式對比
特性 | sys.usb.configfs=0 (傳統模式) | sys.usb.configfs=1 (現代模式) |
---|---|---|
技術名稱 | android_usb / gadgetfs | configfs USB Gadget |
出現時間 | Android 早期 | Android 6.0+ 逐漸引入 |
配置方式 | 寫?/sys/class/android_usb/ | 使用?configfs ?虛擬文件系統 |
靈活性 | 較低 | 極高(支持復合設備、自定義描述符) |
性能 | 一般 | 更好 |
常見設備 | 老設備、AOSP 默認 | Pixel、三星、華為等新設備 |
? 兩種屬性對比
- sys.usb.configfs是怎么做,即怎么選擇哪種方式配置USB。
- sys.usb.config是做什么,即配置成哪種USB模式:mtp,adb,rndis,accessory等。
- 總結
特性 sys.usb.config
sys.usb.configfs
類型 功能列表(字符串) 模式開關(0/1) 作用 “要什么功能” “用什么方式配置” 影響范圍 用戶可見的 USB 模式 底層實現機制 可變性 頻繁變化(用戶切換模式) 啟動時確定,很少變化 持久化 persist.sys.usb.config
通常硬編碼或由內核決定
1.2 on post-fs-data階段配置
在/data分區掛載后,設置USB功能所需的文件權限和目錄結構。防止普通應用隨意修改USB行為。
on post-fs-datachown system system /sys/class/android_usb/android0/f_mass_storage/lun/filechmod 0660 /sys/class/android_usb/android0/f_mass_storage/lun/filechown system system /sys/class/android_usb/android0/f_rndis/ethaddrchmod 0660 /sys/class/android_usb/android0/f_rndis/ethaddrmkdir /data/misc/adb 02750 system shellmkdir /data/adb 0700 root root encryption=Require
f_mass_storage/lun/file
:U盤模式下要暴露的鏡像文件(通常是?/dev/null
?或某個映像)f_rndis/ethaddr
:RNDIS 網絡共享時的 MAC 地址配置- 創建?
/data/misc/adb
:存放 ADB 調試相關密鑰(adb_keys
)- 創建?
/data/adb
:高權限 ADB 目錄(某些定制 ROM 使用)
2. 定義adbd的守護服務
service adbd /system/bin/adbd --root_seclabel=u:r:su:s0class coresocket adbd seqpacket 660 system systemdisabledupdatableseclabel u:r:adbd:s0
adbd服務默認不啟動,由init.<platform>.usb.rc中通過start adbd啟動。這里以高通平臺為例,在init.qcom.usb.rc中會啟動該adb的守護進程,eg:
on property:sys.usb.config=diag,diag_mdm,qdss,qdss_mdm,serial_cdev,serial_cdev_mdm,dpl,rmnet,adb && property:sys.usb.configfs=1start adbd
?
3. 同步廠商的USB屬性到系統屬性
on property:vendor.sys.usb.adb.disabled=*setprop sys.usb.adb.disabled ${vendor.sys.usb.adb.disabled}
只要
vendor.sys.usb.adb.disabled屬性變化,就更新系統屬性
sys.usb.adb.disabled的值。其中“*”表示任何值變化都觸發。
4. USB配置屬性變化時,則修改內核對應的USB配置
init.usb.rc中配置了傳統的USB配置,是為了適配老機型。不同的平臺或者廠商可以實現configfs架構來動態配置USB,例如高通平臺中就是在
init.qcom.usb.rc中配置新的USB屬性。
4.1 傳統的USB動態配置
sys.usb.config的取值由none(關閉USB), adb(ADB調試模式),accessory(當前設備作為配件,連接主機(例如汽車)),audio_source(當前設備作為音頻源輸出),以及幾種的組合。
當sys.usb.config變化時,同時還要滿足property:sys.usb.configfs=0時才會修改內核的USB配置。
例如:
# audio accessory configuration, with adb
on property:sys.usb.config=audio_source,adb && property:sys.usb.configfs=0write /sys/class/android_usb/android0/enable 0write /sys/class/android_usb/android0/idVendor 18d1write /sys/class/android_usb/android0/idProduct 2d03write /sys/class/android_usb/android0/functions ${sys.usb.config}write /sys/class/android_usb/android0/enable 1start adbdsetprop sys.usb.state ${sys.usb.config}
- android_usb是內核包括給用戶空間的USB驅動接口,android0表示是該啟動的第一個實例,大多設備只有一個USB實例。
- enable 0表示安全關閉當前USB,設置新的配置之前先關閉,然后在修改VID和PID以及功能。
- idVendor表示廠商表示,即Vendo ID,
18d1
?是?Google 的官方 VID(十六進制)。- idProduct表示產品型號標識,即Product ID,
2d03
(十六進制)是?AOSP 中“音頻源 + ADB”模式的專用 PID。PID取值還有:
PID (hex) 模式 2d00
accessory(配件模式) 2d01
accessory + adb 2d02
audio_source(音頻源) 2d03
audio_source + adb?? 2d04
accessory + audio_source 2d05
accessory + audio_source + adb - functions決定啟用哪些USB功能,取值是${sys.usb.config}
- enable 1表示激活新的USB配置,內核會根據前面設置的?
idVendor
、idProduct
、functions
?創建一個新的 USB 設備,電腦端會“重新識別設備”(就像拔掉再插上)。
# Used to disable USB when switching states
on property:sys.usb.config=none && property:sys.usb.configfs=0stop adbdwrite /sys/class/android_usb/android0/enable 0write /sys/class/android_usb/android0/bDeviceClass 0setprop sys.usb.state ${sys.usb.config}
?總結
配置項 | 取值 | 含義 / 用途 | 典型場景 |
---|---|---|---|
sys.usb.configfs | 0 | 使用傳統?android_usb ?驅動(舊方式) | AOSP、老設備 |
1 | 使用現代?configfs ?USB Gadget(新方式) | Pixel、三星、華為新機 | |
sys.usb.config | none | 僅充電,無數據功能 | 用戶選擇“僅充電” |
adb | 僅 ADB 調試 | 開發者模式調試 | |
accessory | Android Open Accessory 模式,當前設備作為配件,連接主機 | 連接 Arduino、汽車主機 | |
audio_source | 音頻源輸出(手機→外部設備) | 連車載音響播放音樂 | |
accessory, adb | 即支持配件模式,也支持adb | 手機共享網絡給電腦 | |
audio_source,adb | 音源輸出+adb | 連車載音響播放音樂、設備調試 | |
accessory,audio_source | 即支持Android Open Accessory 模式,當前設備作為配件,連接主機; 也作為音源輸出 | 連接汽車主機,并作為音源輸出 | |
accessory,audio_source,adb | Accessory + 調試 | 開發調試配件 |
4.2 使用configs動態配置USB
該章節以高通平臺為例,請參考下一個。
5 USB Type-c的模式/角色/充電控制
5.1 USB Type-C模式控制
當屬性sys.usb.typec.mode發生變化時,則寫入內核dual_role_usb接口讓內核切換角色。
- dfp(Downstream Facing Port):主機模式(Host),支持OTG(on the go)功能
ufp
?(Upstream Facing Port):設備模式(Device)場景 手機角色 對方設備角色 手機連電腦傳照片 UFP(設備) 電腦是 DFP(主機) 手機接 OTG + U盤 DFP(主機) U盤是 UFP(設備) 手機給另一臺手機充電 DFP(電源/主機) 對方是 UFP(受電/設備 # USB mode changes on property:sys.usb.typec.mode=dfpwrite /sys/class/dual_role_usb/otg_default/mode ${sys.usb.typec.mode}setprop sys.usb.typec.state ${sys.usb.typec.mode}on property:sys.usb.typec.mode=ufpwrite /sys/class/dual_role_usb/otg_default/mode ${sys.usb.typec.mode}setprop sys.usb.typec.state ${sys.usb.typec.mode}
5.2?USB Type-C角色控制
當屬性sys.usb.typec.data_role變化時,取值device和host,通過dual_role_usb修改設備的充當的角色,并更新sys.usb.typec.state的屬性值。
- 取值device時,告訴內核要作為USB設備,即UFP模式。
- 取值host時,告訴內核要作為USB主機,即DFP模式。
# USB data role changes
on property:sys.usb.typec.data_role=devicewrite /sys/class/dual_role_usb/otg_default/data_role ${sys.usb.typec.data_role}setprop sys.usb.typec.state ${sys.usb.typec.data_role}on property:sys.usb.typec.data_role=hostwrite /sys/class/dual_role_usb/otg_default/data_role ${sys.usb.typec.data_role}setprop sys.usb.typec.state ${sys.usb.typec.data_role}
5.3 TypeC mode和 TypeC role的對比
這兩個屬性是Android采用“策略與機制分離”的設計原則,role是請求,mode是執行。
概念 | typec.data_role | typec.mode |
---|---|---|
層級 | 系統/策略層 | 硬件/內核層 |
作用 | 表達系統意圖(我要當主機) | 直接控制硬件角色(變成主機) |
類比 | “我要加速”,是“請求” | “踩油門”,是“執行” |
是否可被覆蓋 | 是(可被電源管理等策略干預) | 否 |
誰設置它 | 系統服務(如 UsbDeviceManager) | int /HAL/ 內核 |
設計目的 | 策略(policy) | 機制(mechanism) |
5.4 USB type-c充電角色控制
當屬性sys.usb.typec.power_role變化時,取值source和sink,通過dual_role_usb控制誰給誰充電,實現反向充電和被充電,并更新sys.usb.typec.state的屬性值。
- source: 我是電源,可以給其他設備充電
- sink:我是負載,需要被充電
# USB power role changes
on property:sys.usb.typec.power_role=sourcewrite /sys/class/dual_role_usb/otg_default/power_role ${sys.usb.typec.power_role}setprop sys.usb.typec.state ${sys.usb.typec.power_role}on property:sys.usb.typec.power_role=sinkwrite /sys/class/dual_role_usb/otg_default/power_role ${sys.usb.typec.power_role}setprop sys.usb.typec.state ${sys.usb.typec.power_role}
注意:power_role和data_role是相互獨立,前者控制電源角色,后者控制數據角色。