文章目錄
- AIDL的原理
- 構建AIDL的流程
- 往凍結的AIDL中加接口
AIDL的原理
可以利用ALDL定義客戶端與服務均認可的編程接口,以便二者使用進程間通信 (IPC) 進行相互通信。在 Android 中,一個進程通常無法訪問另一個進程的內存。因此,為進行通信,進程需將其對象分解成可供操作系統理解的原語,并將其編組為可供您操作的對象。編寫執行該編組操作的代碼較為繁瑣,因此 Android 會使用 AIDL 為您處理此問題。
AIDL 可以理解成是一個范式, 通過這個范式編寫接口文件, 然后利用Android的AIDL工具 會生成繼承binder所需要能力的頭文件。
構建AIDL的流程
以automotive的audiocontrol模塊為例
- 編寫AIDL接口文件,編寫Android.bp, 通過AIDL 生成頭文件
其aidl的文件位于下面的目錄
hardware/interfaces/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/
編譯會在下面的目錄生成實現binder通信的接口文件。
接口文件有java cpp ndk三種類型。 使得能夠被不同的客戶端和服務端的代碼引用到。
out/soong/.intermediates/hardware/interfaces/automotive/audiocontrol/aidl/android.hardware.automotive.audiocontrol-V2-cpp-source/gen/include/android/hardware/automotive/audiocontrol$ ls
AudioFocusChange.h BnFocusListener.h BpDuckingInfo.h IAudioControl.h
BnAudioControl.h BnMutingInfo.h BpFocusListener.h IFocusListener.h
BnAudioFocusChange.h BpAudioControl.h BpMutingInfo.h MutingInfo.h
BnDuckingInfo.h BpAudioFocusChange.h DuckingInfo.h
- 實現service,實現service對應的bin,以及rc,注冊服務到servicemananger
AudioContro 實現的demo bin位于hardware/interfaces/automotive/audiocontrol/aidl/default
目錄下,編譯會生成
android.hardware.automotive.audiocontrol-service.example這樣的bin 這個bin在 audiocontrol-default.rc 中啟動。
當然服務端的是 就是把audiocontrol的服務注冊到servicemanger中。
std::shared_ptr<AudioControl> audioControl = ::ndk::SharedRefBase::make<AudioControl>();const std::string instance = std::string() + AudioControl::descriptor + "/default";binder_status_t status =AServiceManager_addService(audioControl->asBinder().get(), instance.c_str());CHECK_EQ(status, STATUS_OK);
服務的名字在audiocontrol-default.xml中定義為
android.hardware.automotive.audiocontrol.IAudioControl/default
- 實現client,獲取service,調用service相關的接口。
clinet 端 主要是通過名字從serviceManager 中獲取到audioControl的服務。然后通過服務調用其接口。
如下通過getService 獲取服務,然后通過名字獲取IAudioControl對象。然后就可以調用其函數了
private static final String AUDIO_CONTROL_SERVICE ="android.hardware.automotive.audiocontrol.IAudioControl/default";private IBinder mBinder;private IAudioControl mAudioControl;private boolean mListenerRegistered = false;private AudioControlDeathRecipient mDeathRecipient;static @Nullable IBinder getService() {return Binder.allowBlocking(ServiceManager.waitForDeclaredService(AUDIO_CONTROL_SERVICE));}AudioControlWrapperAidl(IBinder binder) {mBinder = Objects.requireNonNull(binder);mAudioControl = IAudioControl.Stub.asInterface(binder);}IBinder binder = AudioControlWrapperAidl.getService();
if (binder != null) {return new AudioControlWrapperAidl(binder);
}@Overridepublic void onAudioFocusChange(@AttributeUsage int usage, int zoneId, int focusChange) {if (Slogf.isLoggable(TAG, Log.DEBUG)) {Slogf.d(TAG, "onAudioFocusChange: usage " + usageToString(usage)+ ", zoneId " + zoneId + ", focusChange " + focusChange);}try {String usageName = usageToXsdString(usage);mAudioControl.onAudioFocusChange(usageName, zoneId, focusChange);} catch (RemoteException e) {throw new IllegalStateException("Failed to query IAudioControl#onAudioFocusChange", e);}}
往凍結的AIDL中加接口
按照Android規則來說 發布之后的AIDL接口是不能修改的。 有相應的Freeze AIDL APIs處理。 從提交記錄看 freeze 的操作是加hash值。
diff --git a/automotive/audiocontrol/aidl/Android.bp b/automotive/audiocontrol/aidl/Android.bp
index 7a947d3ab..4acfd82d6 100644
--- a/automotive/audiocontrol/aidl/Android.bp
+++ b/automotive/audiocontrol/aidl/Android.bp
@@ -19,4 +19,5 @@ aidl_interface {
sdk_version: "module_current",
},
},
+ versions: ["1"],
}
diff --git a/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/1/.hash b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/1/.hash
new file mode 100644
index 000000000..c4bb36b47
--- /dev/null
+++ b/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/1/.hash
@@ -0,0 +1 @@
+ba2a7caca61683385b3b100e4faab1b4139fc547
看提交記錄加接口的地方:
- /aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl
- /aidl/default/AudioControl.h
- /aidl/default/AudioControl.cpp
diff --git a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl
index 4b03af11a..3a0224557 100644
--- a/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidl
+++ b/automotive/audiocontrol/aidl/android/hardware/automotive/audiocontrol/IAudioControl.aidldiff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp
index 748947cb2..b076d0128 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.cpp
+++ b/automotive/audiocontrol/aidl/default/AudioControl.cppdiff --git a/automotive/audiocontrol/aidl/default/AudioControl.h b/automotive/audiocontrol/aidl/default/AudioControl.h
index cf5694762..ab0b1b305 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.h
+++ b/automotive/audiocontrol/aidl/default/AudioControl.h
- 出現AIDL修改報錯
Above AIDL file(s) has changed and this is NEVER allowed on a release platform
(i.e., PLATFORM_VERSION_CODENAME is REL). If a device is shipped with this
change by ignoring this message, it has a high risk of breaking later when a
module using the interface is updated, e.g., Maineline modules.
11:47:01 ninja failed with: exit status 1
報錯的原因解釋:
stability :此接口的穩定性承諾的可選標志。目前僅支持"vintf" 。如果未設置,則對應于在此編譯上下文中具有穩定性的接口(因此此處加載的接口只能與一起編譯的東西一起使用,例如在 system.img 上)。如果將其設置為"vintf" ,則這對應于穩定性承諾:接口必須在使用期間保持穩定。
解決: 所有的AIDL有關地方的接口都要增加。
- 出現hash校驗錯誤:
hardware/interfaces/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocont FAILED: out/soong/.intermediates/hardware/interfaces/automotive/audiocontrol/aidl/android.hardware.automotive.audiocontrol-api/checkhash_1.timestamp if [ $(cd 'hardware/interfaces/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/1' && { find ./ -name "*.aidl" -print0 | LC_ALL=C sort -z | xargs -0 sha1sum && echo latest-version; } | sha1sum | cut -d " " -f 1) = $(read -r <'hardware/interfaces/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/1/.hash' hash extra; printf %s $hash) ]; then touch out/soong/.intermediates/hardware/interfaces/automotive/audiocontrol/aidl/android.hardware.automotive.audiocontrol-api/checkhash_1.timestamp; else cat 'system/tools/aidl/build/message_check_integrity.txt' && exit 1; fi ############################################################################### # ERROR: Modification detected of stable AIDL API file # ############################################################################### Above AIDL file(s) has changed, resulting in a different hash. Hash values may be checked at runtime to verify interface stability. If a device is shipped with this change by ignoring this message, it has a high risk of breaking later when a module using the interface is updated, e.g., Mainline modules. 16:41:52 ninja failed with: exit status 1
錯誤原因:
構建過程未能驗證 AIDL 文件的哈希值,表明發生了修改。
哈希檢查腳本:bash
if [ $(cd 'hardware/interfaces/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/1' && { find ./ -name "*.aidl" -print0 | LC_ALL=C sort -z | xargs -0 sha1sum && echo latest-version; } | sha1sum | cut -d " " -f 1) = $(read -r <'hardware/interfaces/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/1/.hash' hash extra; printf %s $hash) ]; then touch out/soong/.intermediates/hardware/interfaces/automotive/audiocontrol/aidl/android.hardware.automotive.audiocontrol-api/checkhash_1.timestamp; else cat 'system/tools/aidl/build/message_check_integrity.txt' && exit 1; fi
這是檢查 AIDL 文件哈希值是否與預期哈希值匹配的腳本。如果哈希值匹配,構建過程將繼續進行;否則,將引發錯誤。錯誤消息:makefile
ERROR: Modification detected of stable AIDL API file
- 修改hash值。
根據報錯的提交腳本。使用下面的腳本在對應的目錄下生成hash 值, 將這個hash值替換到.hash文件即可
目錄hardware/interfaces/automotive/audiocontrol/aidl/aidl_api/android.hardware.automotive.audiocontrol/1
{ find ./ -name "*.aidl" -print0 | LC_ALL=C sort -z | xargs -0 sha1sum && echo latest-version; } | sha1sum | cut -d " " -f 1
- 出現這個錯誤
Android will be dropped but finished with status UNKNOWN_TRANSACTION
需要push 所有system/lib底下有關的audiocontrol的so、
使用版本化接口接口方法在運行時,當嘗試在舊服務器上調用新方法時,新客戶端會收到錯誤或異常,具體取決于后端。
cpp后端獲取::android::UNKNOWN_TRANSACTION 。
ndk后端獲取STATUS_UNKNOWN_TRANSACTION 。
java后端獲取android.os.RemoteException并顯示一條消息,說明 API 未實現。
總結: 在凍結的AIDL接口上面加新的接口 需要做的步驟。 但是強烈不建議這么做,可以自己單獨實現一個AIDL接口、AIDL的服務、以及上層的實現
- 修改AIDL文件 添加接口
- 計算Hash,修改hash 值
- 編譯push 生成的so
- 在應用上層獲取服務就可以調用到新的接口了。