Android 14 推出了新的遠端存取功能,讓合作夥伴可遠端喚醒車輛中的 Android 裝置,執行特定工作。例如,在夜間執行車庫模式以套用軟體更新。端對端工作流程需要多個非 Android 元件。Android 不會為非 Android 元件定義或提供實作方式 (這項責任屬於您)。
詳情請參閱以下各節說明:
工作流程。用於用戶端註冊和工作提交的範例架構中,多個元件之間的工作流程。
編寫遠端工作用戶端。使用遠端存取權,並瞭解如何編寫遠端工作用戶端。
供應商實作:範例架構中的廠商元件支援遠端存取。
恢復原廠設定和轉移擁有權。瞭解如何處理恢復原廠設定和車輛擁有權轉移程序。
測試遠端存取用戶端。瞭解如何測試遠端存取功能。
建築
以下內容假設使用以下架構示例,但這只是假設,可能不反映實際架構。原始設備製造商 (OEM) 應根據其車輛和伺服器架構,調整實際導入方式。
圖 1. 架構範例。
這個範例架構包含下列硬體元件:
硬體元件 | 說明 |
---|---|
應用程式處理器 | 執行 Android 的處理器。Android 可能會在這個處理器的虛擬記憶體 (VM) 上執行 (而非在實際硬體上執行)。 |
車輛處理器 | 負責控制應用程式處理器電力的處理器。 |
車輛遠端資訊控制單元 (TCU) | 車輛中的處理器一律可接收來自雲端的遠端訊息。假設 TCU 一律處於開啟或低耗電模式。使用遠端訊息喚醒 TCU。 |
喚醒伺服器 | 在雲端執行的遠端伺服器,負責與車輛中的 TCU 通訊,以便發出喚醒指令。 |
遠端工作伺服器 | 遠端工作伺服器在雲端執行,並會與使用者互動及管理遠端工作。 |
範例架構包含下列軟體元件,所有元件都會在 Android 上執行:
Android 上的軟體元件 | 說明 |
---|---|
車用服務 | 提供遠端存取 API 的 AAOS 架構服務。 |
遠端工作用戶端 | 由供應商編寫的 Service 類別,可執行遠端工作。一個 Android 系統可以執行多個遠端工作用戶端。 |
遠端存取 HAL | 必須實作才能進行遠端存取。 用於 AAOS 與非 Android 元件 (例如 TCU) 之間通訊的抽象層。 |
以下說明非 Android 軟體元件:
非 Android 軟體元件 | 說明 |
---|---|
喚醒用戶端 | 在 TCU 上執行的軟體,可與喚醒伺服器維持長期連線。它也會與遠端存取 HAL 保持連線,以便將遠端工作提交給 Car Service。 |
喚醒伺服器實作 | 與在 TCU 上執行的喚醒用戶端通訊的伺服器。可以向喚醒用戶端傳送喚醒要求。 |
遠端工作伺服器實作 | 管理遠端工作的伺服器。使用者會與此伺服器互動,以發出及監控遠端工作。 |
工作流程
本節列出範例工作流程中的步驟。
工作流程範例
詳細的工作流程可以類似下列內容:
使用者將車輛停在車庫。
合作夥伴會在車輛互動不太可能發生的情況下,於夜間更新車輛。
合作夥伴雲端伺服器將更新系統遠端工作傳送至車輛。具體來說,就是車輛的通訊控制單元 (TCU)。
車輛的 TCU 會喚醒 Android 電子控制單元 (ECU),而原始設備製造商 (OEM) 服務會觸發車庫模式。
Android 會在 Garage 模式下執行,透過 Google Play 下載及安裝更新。
套用更新後,Android 會將工作標示為完成,並結束連線或達到指定的逾時期限。
詳細工作流程
遠端存取需要完成兩個重要步驟。第一步是註冊用戶端,也就是將特定使用者連結至在特定車輛上執行的特定遠端工作用戶端。另一個是提交工作,也就是將特定使用者的遠端工作提交至在特定車輛上執行的特定遠端工作用戶端。
註冊用戶端
如要使用遠端存取功能,使用者必須至少開啟遠端工作用戶端應用程式一次,並完成用戶端註冊程序 (粗體文字表示 AAOS 實作的工作):
在開機時,車輛服務會從遠端存取 HAL 取得車輛資訊。
在啟動時,Car Service 會根據意圖篩選器和權限,啟動所有遠端工作用戶端。
在遠端工作主體用戶端啟動時,遠端工作主體用戶端會向 Car Service 註冊。
Car Service 會通知遠端工作用戶端註冊資訊,包括車輛 ID 和用戶端 ID。用戶端 ID 是唯一的 ID,由 Car Service 指派給這個用戶端。保證在同一輛車的所有遠端工作用戶端中不重複。
使用者透過遠端工作任務用戶端登入遠端工作任務伺服器,並為這輛車輛啟用遠端存取功能。這個步驟通常會透過遠端工作伺服器進行驗證。
遠端工作主體用戶端會將使用者資訊連同車輛 ID 和用戶端 ID 上傳至遠端工作主體伺服器,並要求伺服器將使用者與這個特定用戶端和車輛建立連結。
視情況而定,這個步驟可能會要求使用者提供額外的雙重驗證。
遠端工作伺服器必須驗證要求中提供的車輛 ID 是否與傳送者的車輛 ID 相符,這可以透過車輛認證來完成。
除非恢復原廠設定,每輛車的使用者都必須完成用戶端註冊程序。用戶端 ID 會儲存在 Car Service 的本機,且對於相同用戶端會保持不變。
圖 2. 註冊用戶端。
取消註冊用戶端
使用者可以透過車輛或遠端工作排程伺服器,將車輛與帳戶取消連結:
在車輛上,使用者可以開啟遠端工作用戶端應用程式,並發出取消連結要求,以取消此車輛與先前連結使用者帳戶的連結。
在遠端工作伺服器上,使用者可以登入帳戶,並取消連結先前已連結的車輛。
如果使用者取消車輛與帳戶的連結,遠端工作伺服器必須移除特定使用者儲存的對應項目。
提交工作
儲存在雲端:
使用者使用遠端工作伺服器,將遠端工作傳送至特定車輛。
遠端工作伺服器會將使用者 ID 對應至車輛 ID 和用戶端 ID。並將工作資料、車輛 ID 和用戶端 ID 傳送至喚醒伺服器。
喚醒伺服器會找出車輛 ID 的特定 TCU (假設已完成 TCU 註冊),並將工作資料和用戶端 ID 傳送至 TCU。
車輛 (粗體文字表示由 AAOS 執行的工作):
TCU 會從遠端伺服器接收遠端工作。
如果執行 AAOS 的應用程式處理器 (AP) 關閉,TCU 會使用車輛處理器 (VP) 喚醒 AP。
車輛服務接收來自 TCU 的工作。
Car Service 會將工作分配給對應的遠端工作用戶端。
遠端工作用戶端會接收並執行工作。
(選用) 遠端工作主體客戶端會與工作伺服器聯絡,取得更多工作詳細資料並執行工作。
(選用) 遠端工作任務用戶端服務將工作結果回報給工作伺服器。
遠端工作用戶端會在工作完成時通知車用服務。
如果需要,車輛服務會還原車輛的電源狀態。
圖 3. 交付工作。
編寫遠端工作用戶端
CarRemoteAccessManager
提供遠端存取功能的 API。詳情請參閱 CarRemoteAccessManager。遠端工作用戶端是執行遠端工作並使用 CarRemoteAccessManager
的 Android 服務。這需要 PERMISSION_USE_REMOTE_ACCESS
和 PERMISSION_CONTROL_REMOTE_ACCESS
,且必須為 RemoteTaskClientService
宣告意圖篩選器,例如:
<service android:name=".remoteaccess.RemoteTaskClientService"
android:directBootAware="true"
android:exported="true">
<intent-filter>
<action android:name="android.car.remoteaccess.RemoteTaskClientService" />
</intent-filter>
</service>
遠端工作用戶端應在建立期間將自己註冊至 Car Service:
public final class RemoteTaskClientService extends Service {
@Override
public void onCreate() {
// mCar = Car.createCar()...
mRemoteAccessManager = (CarRemoteAccessManager)
mcar.getCarManager(Car.CAR_REMOTE_ACCESS_SERVICE);
if (mRemoteAccessManager == null) {
// Remote access feature is not supported.
return;
}
mRemoteAccessManager.setRemoteTaskClient(executor, mRemoteTaskClient);
}
}
必須覆寫 onBind 函式,才能傳回空值。
@Override
public IBinder onBind(Intent intent) {
return null;
}
Car Service 會管理其生命週期。Car Service 會在啟動期間和接收遠端工作時繫結至此服務。車輛服務會在工作完成後解除綁定這項服務。詳情請參閱「管理服務的生命週期」一文。
遠端工作主體會以系統使用者的身分執行,因此無法存取任何特定使用者資料。
以下範例說明如何處理已註冊的回呼:
private final class RemoteTaskClient
implements CarRemoteAccessManager.RemoteTaskClientCallback {
@Override
public void onRegistrationUpdated(
RemoteTaskClientRegistrationInfo info) {
// Register to remote task server using info.
}
@Override
public void onRemoteTaskRequested(String taskId,
byte[] data, int remainingTimeSec) {
// Parses the data and execute the task.
// Report task result to remote task server.
mRemoteAccessManager.reportRemoteTaskDone(taskId);
}
@Override
public void onShutdownStarting(CompleteableRemoteTaskFuture future) {
// Stop the executing task.
// Clear the pending task queue.
future.complete();
}
}
供應商實作
遠端存取功能為選用功能,預設為停用。如要啟用這項功能,請新增 RRO,例如以下內容:
// res/xml/overlays.xml
<?xml version="1.0" encoding="utf-8"?>
<overlay>
<item target="array/config_allowed_optional_car_features" value="@array/config_allowed_optional_car_features" />
</overlay>
// res/values/config.xml
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string-array translatable="false" name="config_allowed_optional_car_features">
<item>car_remote_access_service</item>
</string-array>
</resources>
// Android.bp
runtime_resource_overlay {
name: "RemoteAccessOverlay",
resource_dirs: ["res"],
manifest: "AndroidManifest.xml",
sdk_version: "current",
product_specific: true
}
或者,在 userdebug/eng 版本上使用下列 ADB 指令:
adb shell cmd car_service enable-feature car_remote_access_service
Android 作業系統需求
遠端存取 HAL
遠端存取硬體抽象層 (HAL) 是由廠商導入的抽象層,用於 AAOS 和其他 ECU (例如 TCU) 之間的通訊。必須支援遠端存取功能。如未實作遠端存取功能,就不需要實作這項功能。
介面定義於 IRemoteAccess.aidl,並包含以下方法:
類別 | 說明 |
---|---|
String getVehicleId() |
取得可供喚醒伺服器辨識的專屬車輛 ID。 |
String getWakeupServiceName() |
取得遠端喚醒伺服器的名稱。 |
String getProcessorId() |
取得可透過喚醒用戶端辨識的專屬處理器 ID。 |
void setRemoteTaskCallback(IRemoteTaskCallback callback)
設定在要求遠端工作時要呼叫的回呼。 |
|
void clearRemoteTaskCallback() |
清除先前設定的遠端工作回呼。 |
void notifyApStateChange(in ApState state)
偵測應用程式處理器是否準備好接收遠端工作。 |
回呼介面是在 IRemoteTaskCallback.aid
中定義。
類別 | 說明 |
---|---|
oneway void onRemoteTaskRequested(String clientId, in byte[] data)
要求遠端工作時呼叫的回呼。 |
請參閱使用外部 TCU 的參考實作項目。實作項目會使用長效讀取串流來接收遠端工作,並支援下列 debug
指令:
dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default
車用 HAL
如要支援遠端存取功能,VHAL 必須支援下列屬性:
類別 | 說明 |
---|---|
SHUTDOWN_REQUEST |
要求關閉車用運算主機。 |
VEHICLE_IN_USE |
|
詳情請參閱「支援的系統屬性」。
靜音模式
遠端存取功能必須支援靜音模式,這樣車輛才能在無人時以靜音模式啟動,執行遠端工作。在靜音模式下,AAOS 裝置會在螢幕和音訊關閉的情況下啟動。
靜音模式是透過兩個 Linux 核心 sysfs
檔案控制。
類別 | 說明 |
---|---|
/sys/kernel/silent_boot/pm_silentmode_kernel_state
代表目前的靜音模式。 |
|
/sys/kernel/silent_boot/pm_silentmode_hw_state
代表設定新靜音模式的硬體訊號。 |
車輛處理器會將硬體訊號傳送至 Android SoC,以開啟/關閉靜音模式。信號 (0 或 1) 會寫入 /sys/kernel/silent_boot/pm_silentmode_hw_state
。接著,AAOS 架構會相應更新 /sys/kernel/silent_boot/pm_silentmode_kernel_state
,代表目前的靜音模式。AAOS 模組會檢查 /sys/kernel/silent_boot/pm_silentmode_kernel_state
,瞭解系統是否處於靜音模式。
收到遠端工作且 AAOS 啟動時,車輛處理器會設定靜音模式並啟動 AAOS,讓系統在螢幕/音訊關閉的情況下啟動。
車輛內的非 Android 元件
車輛處理器
車輛處理器是車輛中的處理器,可控制執行 Android 的應用程式處理器的電源。在範例架構中,TCU 會透過向車輛處理器傳送信號來喚醒應用程式處理器。
車用非 Android 元件
車輛 TCU 隨時可以接收遠端訊息。
喚醒用戶端會在 TCU 上執行,確保與遠端喚醒伺服器的連線可長時間維持。
在 AP 上執行的 AAOS 可透過遠端存取 HAL 與在 TCU 上執行的喚醒用戶端通訊。
圖 4. TCU (喚醒用戶端)。
雲端元件
喚醒伺服器
喚醒伺服器會與 TCU 上的喚醒用戶端進行通訊,以執行下列操作:
- 與車輛的 TCU 保持長久連線。
- 根據車輛 ID 尋找特定 TCU。
- 回報車輛狀態。例如,線上或離線,或上次連線至遠端工作伺服器的時間。
在實際的實作中,喚醒伺服器可以與遠端工作伺服器合併。
遠端工作伺服器
遠端工作伺服器會管理這些遠端工作。
使用者與伺服器互動,啟動新的遠端工作及監控遠端工作。
使用遠端喚醒伺服器喚醒車輛中的應用程式處理器。
與在車輛上執行的遠端工作用戶端互動。
儲存客戶註冊資訊。這會將特定使用者與特定車輛上的特定遠端工作用戶端建立關聯。
通常,透過遠端工作伺服器傳送至喚醒伺服器、車輛的 TCU,最後傳送至遠端工作用戶端的工作資料,只是工作 ID。遠端工作用戶端會使用工作 ID 從遠端工作伺服器擷取詳細資訊。
隱私權和安全性規定
工作 | Condition | 必要性 |
---|---|---|
TCU (喚醒用戶端) | 必須 |
|
喚醒伺服器 | 必須 |
|
遠端工作用戶端 | 必須 |
|
遠端工作伺服器 | 必須 |
|
恢復原廠設定和轉移擁有權
如果使用者執行恢復原廠設定,系統會清除儲存在 Car Service 中的用戶端 ID。不過,系統不會通知伺服器 (遠端工作排程伺服器和遠端喚醒伺服器)。伺服器會保留從已過期的用戶端 ID 到車輛的對應關係。因此,如果使用者為車輛啟動新的遠端工作,系統會使用已過期的用戶端 ID。車輛已喚醒,但由於遠端工作用戶端的用戶端 ID 不符,因此無法執行遠端工作。
以下說明一種可能的恢復原廠設定實作方式。
當使用者執行原廠重設時,供應商會提示使用者登入遠端工作伺服器,並取消連結車輛與帳戶的連結 (如果使用者先前已連結車輛)。裝置在恢復原廠設定期間可能無法連上網路。因此,在裝置恢復原廠設定時發出取消連結要求可能不切實際。
每當車輛所有權轉移時,都應執行一些作業,確保前車主無法再向車輛發出遠端工作。舉例來說,我們可能會要求新擁有者:
將裝置恢復原廠設定。確保系統重新產生用戶端 ID。完成這個步驟後,先前的擁有者仍可喚醒車輛,但無法再執行遠端工作。
開啟遠端工作用戶端應用程式,並按照「取消註冊用戶端」程序,將車輛與先前擁有者的帳戶取消連結。新擁有者可以按照註冊用戶端程序,將車輛連結至自己的帳戶,並取代先前連結的帳戶。
測試遠端工作用戶端
我們提供參考遠端存取 HAL default
目錄,以便測試遠端工作用戶端。您可以使用下列 debug
指令,將假的遠端工作插入 HAL,如果您提供正確的用戶端 ID,系統會將該工作轉送至遠端工作用戶端。您可以在遠端工作項目用戶端實作中記錄註冊資訊,藉此取得用戶端 ID。
adb root && adb shell dumpsys android.hardware.automotive.remoteaccess.IRemoteAccess/default --inject-task [clientID] [taskData]