Sensors HAL 2.0

感應器硬體抽象層 (HAL) 是 Android 感應器架構與裝置感應器 (例如加速計或陀螺儀) 之間的介面。感應器 HAL 定義必須實作的函式,讓架構控管感應器。

Android 10 以上版本的新裝置和升級裝置,都可使用 Sensors HAL 2.0。感應器 HAL 2.0 是以感應器 HAL 1.0 為基礎,但有幾項主要差異,因此無法回溯相容。感應器 HAL 2.0 會使用快速訊息佇列 (FMQ),將感應器事件從 HAL 傳送至 Android 感應器架構。

Android 11 以上版本適用於新裝置和升級裝置,感應器 HAL 2.1 是感應器 HAL 2.0 的疊代版本,可公開 HINGE_ANGLE 感應器類型,並更新各種方法以接受 HINGE_ANGLE 類型。

HAL 2.1 介面

感應器 HAL 2.1 的主要說明文件來源位於 hardware/interfaces/sensors/2.1/ISensors.hal 的 HAL 定義中。如果本頁面與 ISensors.hal 的規定有所衝突,請以 ISensors.hal 的規定為準。

HAL 2.0 介面

感應器 HAL 2.0 的主要說明文件來源位於 hardware/interfaces/sensors/2.0/ISensors.hal 的 HAL 定義中。如果本頁面與 ISensors.hal 的規定有所衝突,請以 ISensors.hal 的規定為準。

實作 Sensors HAL 2.0 和 HAL 2.1

如要實作 Sensors HAL 2.0 或 2.1,物件必須擴充 ISensors 介面,並實作 2.0/ISensors.hal2.1/ISensors.hal 中定義的所有函式。

初始化 HAL

Android 感應器架構必須先初始化 Sensors HAL,才能使用該 HAL。架構會呼叫 HAL 2.0 的 initialize() 函式和 HAL 2.1 的 initialize_2_1() 函式,為感應器 HAL 提供三個參數:兩個 FMQ 描述元和一個指向 ISensorsCallback 物件的指標。

HAL 會使用第一個描述元建立 Event FMQ,用於將感應器事件寫入架構。HAL 會使用第二個描述元建立 Wake Lock FMQ,用於在 HAL 為感應器事件釋放喚醒鎖定時進行同步。WAKE_UPHAL 必須儲存 ISensorsCallback 物件的指標,以便叫用任何必要的回呼函式。

初始化感應器 HAL 時,必須先呼叫 initialize()initialize_2_1() 函式。

公開可用的感應器

如要取得裝置中所有可用靜態感應器的清單,請使用 HAL 2.0 的 getSensorsList() 函式和 HAL 2.1 的 getSensorsList_2_1() 函式。這個函式會傳回感應器清單,每個感應器都由其控制代碼唯一識別。當代管感應器 HAL 的程序重新啟動時,特定感應器的控制代碼不得變更。裝置重新啟動或系統伺服器重新啟動時,控制代碼可能會變更。

如果多個感應器共用相同的感應器類型和喚醒屬性,則清單中的第一個感應器會稱為「預設」感應器,並傳回給使用 getDefaultSensor(int sensorType, bool wakeUp) 函式的應用程式。

感應器清單的穩定性

感應器 HAL 重新啟動後,如果 getSensorsList()getSensorsList_2_1() 傳回的資料與重新啟動前擷取的感應器清單相比,顯示重大變化,架構就會觸發 Android 執行階段重新啟動。感應器清單的重大變更包括:缺少特定控制代碼的感應器或感應器屬性已變更,或是導入新感應器。雖然重新啟動 Android 執行階段會干擾使用者,但這是必要步驟,因為 Android 架構無法再滿足 Android API 合約,也就是靜態 (非動態) 感應器在應用程式生命週期內不會變更。這也可能導致架構無法重新建立應用程式發出的有效感應器要求。因此,建議 HAL 供應商避免不必要的感應器清單變更。

為確保感應器控制代碼穩定,HAL 必須將裝置中的特定實體感應器確定性地對應至其控制代碼。雖然 Sensors HAL 介面並未強制規定具體實作方式,但開發人員可選擇多種做法來滿足這項需求。

舉例來說,感應器清單可依每個感應器的固定屬性 (例如供應商、型號和感應器類型) 組合排序。另一種做法是依據裝置的靜態感應器組固定在硬體中的事實,因此 HAL 需要知道所有預期感應器何時完成初始化,才能從 getSensorsList()getSensorsList_2_1() 傳回。這份預期感應器清單可以編譯成 HAL 二進位檔,或儲存在檔案系統的設定檔中,而出現順序可用於衍生穩定控制代碼。雖然最佳解決方案取決於 HAL 的具體實作詳細資料,但主要要求是感應器控制代碼在 HAL 重新啟動時不得變更。

設定感應器

啟用感應器前,必須先使用 batch() 函式設定感應器的取樣週期和最長回報延遲時間。

感應器必須能夠隨時使用 batch() 重新設定,且不會遺失感應器資料。

取樣週期

取樣週期會因設定的感應器類型而有不同意義:

  • 連續:感應器事件會以連續速率產生。
  • 變更時:系統產生事件的速度不會快於取樣週期,如果測量值沒有變更,產生事件的速度可能會慢於取樣週期。
  • 單次:系統會忽略取樣週期。
  • 特殊:詳情請參閱「感應器類型」。

如要瞭解取樣週期與感應器回報模式之間的互動,請參閱「回報模式」。

最長回報延遲時間

回報延遲時間上限會設定事件可延遲並儲存在硬體 FIFO 中的時間上限 (以奈秒為單位),之後系統會在 SoC 喚醒時,透過 HAL 將事件寫入 Event FMQ。

如果值為零,表示事件一經測量就必須回報,不是完全略過 FIFO,就是 FIFO 中出現感應器事件時,立即清空 FIFO。

舉例來說,如果加速計以 50 Hz 啟動,且回報延遲時間上限為零,則 SoC 處於喚醒狀態時,每秒會觸發 50 次中斷。

如果最大回報延遲時間大於零,感應器事件就不必在偵測到時立即回報。只要沒有任何事件延遲超過最長回報延遲時間,事件就能暫時儲存在硬體 FIFO 中,並以批次形式回報。系統會記錄並立即傳回前一批次之後的所有事件。這會減少傳送至 SoC 的中斷次數,並讓 SoC 在感應器擷取及批次處理資料時,切換至低功耗模式。

每個事件都有相關聯的時間戳記。延遲回報事件的時間不得影響事件時間戳記。時間戳記必須準確,且對應事件實際發生的時間,而非回報時間。

如要進一步瞭解如何回報感應器事件,以及回報最大回報延遲時間不為零的事件時須遵守的規定,請參閱「批次處理」一節。

啟用感應器

架構會使用 activate() 函式啟用及停用感應器。啟用感應器前,架構必須先使用 batch() 設定感應器。

感應器停用後,不得再將該感應器的其他感應器事件寫入事件 FMQ。

沖水感應器

如果感應器已設定為批次處理感應器資料,架構可以呼叫 flush(),強制立即排清批次處理的感應器事件。這會導致指定感應器控制代碼的批次感應器事件立即寫入 Event FMQ。感應器 HAL 必須在因呼叫 flush() 而寫入的感應器事件結尾,附加清除完成事件。

清除作業會以非同步方式進行 (也就是說,這個函式必須立即傳回)。如果實作方式是為多個感應器使用單一 FIFO,系統只會針對指定感應器排空該 FIFO,並新增排空完成事件。

如果指定的感應器沒有 FIFO (無法緩衝),或 FIFO 在呼叫時為空白,flush() 仍須成功,並為該感應器傳送清除完成事件。這項設定適用於所有感應器,但單次感應器除外。

如果為單次感應器呼叫 flush(),則 flush() 必須傳回 BAD_VALUE,且不會產生清除完成事件。

將感應器事件寫入 FMQ

感應器 HAL 會使用事件 FMQ,將感應器事件推送至 Android 感應器架構。

事件 FMQ 是同步 FMQ,也就是說,如果嘗試寫入 FMQ 的事件數量超過可用空間,寫入作業就會失敗。在這種情況下,HAL 應判斷是否要將目前的事件集寫入為兩組較小的事件,或是在有足夠空間時,將所有事件一起寫入。

當感應器 HAL 將所需數量的感應器事件寫入 Event FMQ 時,感應器 HAL 必須將 EventQueueFlagBits::READ_AND_PROCESS 位元寫入 Event FMQ 的 EventFlag::wake 函式,通知架構事件已準備就緒。您可以使用 EventFlag::createEventFlag 和 Event FMQ 的 getEventFlagWord() 函式,從 Event FMQ 建立 EventFlag。

感應器 HAL 2.0/2.1 支援事件 FMQ 上的 writewriteBlocking。預設實作會提供使用 write 的參照。如果使用 writeBlocking 函式,readNotification 旗標必須設為 EventQueueFlagBits::EVENTS_READ,架構從 Event FMQ 讀取事件時會設定這個旗標。寫入通知旗標必須設為 EventQueueFlagBits::READ_AND_PROCESS,通知架構事件已寫入 Event FMQ。

WAKE_UP 事件

WAKE_UP 事件是感應器事件,會導致應用程式處理器 (AP) 喚醒並立即處理事件。每當 WAKE_UP 事件寫入 Event FMQ 時,感應器 HAL 必須取得喚醒鎖定,確保系統保持喚醒狀態,直到架構可以處理事件為止。收到 WAKE_UP 事件後,架構會確保自身喚醒鎖定,讓感應器 HAL 釋放喚醒鎖定。如要在感應器 HAL 釋放喚醒鎖定時進行同步,請使用喚醒鎖定 FMQ。

感應器 HAL 必須讀取 Wake Lock FMQ,才能判斷架構處理的 WAKE_UP 事件數量。如果未處理的 WAKE_UP 事件總數為零,HAL 應只針對 WAKE_UP 事件釋放喚醒鎖定。 處理感應器事件後,架構會計算標示為 WAKE_UP 事件的事件數量,並將此數字寫回 Wake Lock FMQ。

架構會在將資料寫入 Wake Lock FMQ 時,於 Wake Lock FMQ 上設定 WakeLockQueueFlagBits::DATA_WRITTEN 寫入通知。

動態感應器

動態感應器並非裝置的實體元件,但可做為裝置的輸入內容,例如具有加速計的遊戲手把。

連線動態感應器時,必須從 Sensors HAL 呼叫 ISensorsCallback 中的 onDynamicSensorConnected 函式。這會將新的動態感應器通知架構,並允許透過架構控制感應器,以及讓用戶端使用感應器的事件。

同樣地,動態感應器中斷連線時,必須呼叫 ISensorsCallback 中的 onDynamicSensorDisconnected 函式,架構才能移除不再可用的感應器。

直接管道

直接管道是一種作業方法,可將感應器事件寫入特定記憶體,而非 Event FMQ,藉此略過 Android Sensors Framework。註冊直接管道的用戶端必須直接從用於建立直接管道的記憶體讀取感應器事件,且不會透過架構接收感應器事件。configDirectReport() 函式與正常作業的 batch() 類似,可設定直接回報管道。

registerDirectChannel()unregisterDirectChannel() 函式會建立或終止新的直接管道。

作業模式

setOperationMode() 函式可讓架構設定感應器,以便將感應器資料注入感應器。這項功能可用於測試,特別是架構下方的演算法。

HAL 2.0 中的 injectSensorData() 函式和 HAL 2.0 中的 injectSensorsData_2_1() 函式通常用於將作業參數推送至感應器 HAL。這個函式也可以用來將感應器事件插入特定感應器。

驗證

如要驗證感應器 HAL 的實作情形,請執行感應器 CTS 和 VTS 測試。

CTS 測試

感應器 CTS 測試分為自動化 CTS 測試和手動 CTS 驗證應用程式。

自動化測試位於 cts/tests/sensor/src/android/hardware/cts。 這些測試會驗證感應器的標準功能,例如啟動感應器、批次處理和感應器事件速率。

CTS Verifier 測試位於 cts/apps/CtsVerifier/src/com/android/cts/verifier/sensors。這些測試需要測試人員手動輸入,並確保感應器回報的值準確無誤。

通過 CTS 測試是確保受測裝置符合所有 CDD 要求的關鍵。

VTS 測試

感應器 HAL 2.0 的 VTS 測試位於 hardware/interfaces/sensors/2.0/vts。感應器 HAL 2.1 的 VTS 測試位於 hardware/interfaces/sensors/2.1/vts。這些測試可確保感應器 HAL 實作正確無誤,且ISensors.halISensorsCallback.hal中的所有規定都已妥善遵守。

從 Sensors HAL 2.0 升級至 2.1

從 Sensors HAL 2.0 升級至 2.1 時,HAL 實作項目必須包含 initialize_2_1()getSensorsList_2_1()injectSensorsData_2_1() 方法,以及 HAL 2.1 型別。這些方法必須符合上述 HAL 2.0 的相同規定。

由於次要版本 HAL 必須支援先前 HAL 的所有函式,因此 2.1 HAL 必須支援初始化為 2.0 HAL。為避免支援兩種 HAL 版本帶來的複雜性,強烈建議使用 Multi-HAL 2.1。

如要瞭解如何實作自己的 Sensors 2.1 HAL,請參閱 Sensors.h

從 Sensors HAL 1.0 升級至 2.0

從感應器 HAL 1.0 升級至 2.0 時,請確保 HAL 實作項目符合下列規定。

初始化 HAL

必須支援 initialize() 函式,才能在架構和 HAL 之間建立 FMQ。

公開可用的感應器

在 Sensors HAL 2.0 中,getSensorsList() 函式必須在單一裝置啟動期間傳回相同的值,即使 Sensors HAL 重新啟動也一樣。getSensorsList() 函式的新規定是,即使在感應器 HAL 重新啟動後,也必須在單一裝置啟動期間傳回相同的值。這樣一來,如果系統伺服器重新啟動,架構就能嘗試重新建立感應器連線。裝置重新啟動後,getSensorsList() 傳回的值可能會變更。

將感應器事件寫入 FMQ

在 Sensors HAL 2.0 中,Sensors HAL 必須主動將感應器事件寫入 Event FMQ,而不是等待呼叫 poll()。HAL 也負責將正確位元寫入 EventFlag,在架構內觸發 FMQ 讀取作業。

WAKE_UP 事件

在 Sensors HAL 1.0 中,HAL 可以在將 WAKE_UP 發布至 poll() 後,於後續對 poll() 的任何呼叫中,為任何 WAKE_UP 事件釋放喚醒鎖定,因為這表示架構已處理所有感應器事件,並已視需要取得喚醒鎖定。因為在 Sensors HAL 2.0 中,HAL 不再知道架構何時處理寫入 FMQ 的事件,因此架構可透過 Wake Lock FMQ,在處理 WAKE_UP 事件時通知 HAL。

在 Sensors HAL 2.0 中,Sensors HAL 為 WAKE_UP 事件確保的喚醒鎖定必須以 SensorsHAL_WAKEUP 開頭。

動態感應器

動態感應器是透過 Sensors HAL 1.0 中的 poll() 函式傳回。 感應器 HAL 2.0 要求在動態感應器連線變更時,一律呼叫 ISensorsCallback 中的 onDynamicSensorsConnectedonDynamicSensorsDisconnected。這些回呼函式會透過 initialize() 函式提供的 ISensorsCallback 指標提供。

作業模式

感應器 HAL 2.0 必須支援 WAKE_UP 感應器的 DATA_INJECTION 模式。

支援多個 HAL

感應器 HAL 2.0 和 2.1 支援使用感應器多重 HAL 架構的多重 HAL。如需實作詳細資料,請參閱「從感應器 HAL 1.0 移植」。