Android O 前期預研之三:Android Vehicle HAL
Android Automotive
Android Automotive 是Android Oreo中的一個新的特色功能,從AOSP的程式碼上來看,Android O中已經包含有了從Application到Framework 到HAL的整體框架,這一章節,我們簡單的過以下Android Vehicle 的框架,以及重點看下 Vehicle HAL的東西。總體結構大約是以下這個樣子:
上圖的結構應該是Android Oreo當中比較通用的框架結構了,從Application 到Framework到HAL,跟之前的Android版本相比,之前Framework要不通過binder聯絡上一個Daemon,這個Daemon再去load 相關的HAL,要不就是這些Framework的service直接通過JNI去load 這些個HAL 庫。而現在的Android Oreo則是Framework 與HAL之間直接採用HIDL來做聯絡溝通了。接下來我們從下往上的來把Android Vehicle的框架捋一下吧。首先來分析下Vehicle HAL,通過這個來複習並且實踐下之前研究學習過的Android HIDL.
Android Vehicle HAL
types.hal 定義的是一些資料結構,IVehicle.hal定義的是從Framework往HAL呼叫的介面,而IVehicleCallback.hal則是HAL往Framework 上報回撥的介面。看起來還是挺清晰的吧。
而IVehicle.hal的介面也不是很多,
package [email protected]2.0;
import IVehicleCallback;
interface IVehicle {
/**
* Returns a list of all property configurations supported by this vehicle
* HAL.
*/
getAllPropConfigs() generates (vec<VehiclePropConfig> propConfigs);
/**
* Returns a list of property configurations for given properties.
*
* If requested VehicleProperty wasn't found it must return
* StatusCode::INVALID_ARG, otherwise a list of vehicle property
* configurations with StatusCode::OK
*/
getPropConfigs(vec<int32_t> props)
generates (StatusCode status, vec<VehiclePropConfig> propConfigs);
/**
* Get a vehicle property value.
*
* For VehiclePropertyChangeMode::STATIC properties, this method must always
* return the same value always.
* For VehiclePropertyChangeMode::ON_CHANGE properties, it must return the
* latest available value.
*
* Some properties like AUDIO_VOLUME requires to pass additional data in
* GET request in VehiclePropValue object.
*
* If there is no data available yet, which can happen during initial stage,
* this call must return immediately with an error code of
* StatusCode::TRY_AGAIN.
*/
get(VehiclePropValue requestedPropValue)
generates (StatusCode status, VehiclePropValue propValue);
/**
* Set a vehicle property value.
*
* Timestamp of data must be ignored for set operation.
*
* Setting some properties require having initial state available. If initial
* data is not available yet this call must return StatusCode::TRY_AGAIN.
* For a property with separate power control this call must return
* StatusCode::NOT_AVAILABLE error if property is not powered on.
*/
set(VehiclePropValue propValue) generates (StatusCode status);
/**
* Subscribes to property events.
*
* Clients must be able to subscribe to multiple properties at a time
* depending on data provided in options argument.
*
* @param listener This client must be called on appropriate event.
* @param options List of options to subscribe. SubscribeOption contains
* information such as property Id, area Id, sample rate, etc.
*/
subscribe(IVehicleCallback callback, vec<SubscribeOptions> options)
generates (StatusCode status);
/**
* Unsubscribes from property events.
*
* If this client wasn't subscribed to the given property, this method
* must return StatusCode::INVALID_ARG.
*/
unsubscribe(IVehicleCallback callback, int32_t propId)
generates (StatusCode status);
/**
* Print out debugging state for the vehicle hal.
*
* The text must be in ASCII encoding only.
*
* Performance requirements:
*
* The HAL must return from this call in less than 10ms. This call must avoid
* deadlocks, as it may be called at any point of operation. Any synchronization
* primitives used (such as mutex locks or semaphores) must be acquired
* with a timeout.
*
*/
debugDump() generates (string s);
};
而IVehicle.hal則就更少了:
package [email protected]2.0;
interface IVehicleCallback {
/**
* Event callback happens whenever a variable that the API user has
* subscribed to needs to be reported. This may be based purely on
* threshold and frequency (a regular subscription, see subscribe call's
* arguments) or when the IVehicle#set method was called and the actual
* change needs to be reported.
*
* These callbacks are chunked.
*
* @param values that has been updated.
*/
oneway onPropertyEvent(vec<VehiclePropValue> propValues);
/**
* This method gets called if the client was subscribed to a property using
* SubscribeFlags::SET_CALL flag and IVehicle#set(...) method was called.
*
* These events must be delivered to subscriber immediately without any
* batching.
*
* @param value Value that was set by a client.
*/
oneway onPropertySet(VehiclePropValue propValue);
/**
* Set property value is usually asynchronous operation. Thus even if
* client received StatusCode::OK from the IVehicle::set(...) this
* doesn't guarantee that the value was successfully propagated to the
* vehicle network. If such rare event occurs this method must be called.
*
* @param errorCode - any value from StatusCode enum.
* @param property - a property where error has happened.
* @param areaId - bitmask that specifies in which areas the problem has
* occurred, must be 0 for global properties
*/
oneway onPropertySetError(StatusCode errorCode,
int32_t propId,
int32_t areaId);
};
比較好奇的是這麼些介面就能實現Android 車機的這麼些功能?先還是這麼看看吧,後續仔細研究研究。
Android Vehicle HAL 的編譯
按照我們之前的研究來看看這麼些Android Vehicle HAL被怎麼編譯,編譯成什麼東西。先看.hal檔案編譯生成的標頭檔案:
.hal 檔案生成的CPP檔案:
.h 檔案我們之前也都做過分析,Bp/Bn/Bs 代表啥意思相信都沒忘記吧,在這裡就不多贅述了,而VehicleAll.cpp/VehicleCallbackAll.cpp 裡其實就是那些生成的.h檔案中所定義的C++ Class 檔案的實現,這些相關實現都是寫在這些.cpp檔案當中。
這些.cpp檔案/.h檔案最終會生成一個名叫[email protected]的庫,詳情請參考hardware/interfaces/automotive/vehicle/2.0/Android.bp。
另外參考hardware/interfaces/automotive/vehicle/2.0/default/Android.mk,
hardware/interfaces/automotive/vehicle/2.0/default/impl/目錄下會被編譯出名叫[email protected]的靜態庫,而hardware/interfaces/automotive/vehicle/2.0/default/common/目錄會被編譯出一個名叫[email protected]的靜態庫,而這兩個靜態庫都會去連結上面生成的[email protected]動態庫。
而最終會被編譯成一個可執行程式:
include $(CLEAR_VARS)
LOCAL_MODULE := $(vhal_v2_0)-service
LOCAL_INIT_RC := $(vhal_v2_0)-service.rc
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := \
VehicleService.cpp
LOCAL_SHARED_LIBRARIES := \
libbase \
libhidlbase \
libhidltransport \
liblog \
libprotobuf-cpp-lite \
libutils \
$(vhal_v2_0) \
LOCAL_STATIC_LIBRARIES := \
$(vhal_v2_0)-manager-lib \
$(vhal_v2_0)-default-impl-lib \
$(vhal_v2_0)-libproto-native \
LOCAL_CFLAGS += -Wall -Wextra -Werror
include $(BUILD_EXECUTABLE)
而這個可執行程式會被Init 系統在開機的時候啟動,成為一個Daemon:
service vehicle-hal-2.0 /vendor/bin/hw/[email protected]
class hal
user vehicle_network
group system inet
Android Vehicle HAL 的使用
東西都編譯出來後,我們看看Vehicle HAL怎麼來使用。
1) Android Vehicle HAL Service 端使用:
我們來看下hardware/interfaces/automotive/vehicle/2.0/default/VehicleService.cpp檔案:
int main(int /* argc */, char* /* argv */ []) {
auto store = std::make_unique<VehiclePropertyStore>();
auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get());
auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
auto service = std::make_unique<VehicleHalManager>(hal.get());
configureRpcThreadpool(4, true /* callerWillJoin */);
ALOGI("Registering as service...");
service->registerAsService();
ALOGI("Ready");
joinRpcThreadpool();
}
說實話,剛看到這段程式碼的我是一臉懵逼的,auto是個什麼鬼, std::make_unique是個什麼鬼,這幾年弄的都是JAVA/Android,像這些C++的新規範,新東西越來越層出不窮了,真的是一天不學習就得落伍了哈。
幸虧這個也很簡單, std::make_unique就先等同與new吧,auto的意思就是變數型別在宣告的時候先不確定,等變數被定義的時候根據實際情況來確定變數型別。
其中最關鍵的是這兩句:
auto service = std::make_unique<VehicleHalManager>(hal.get());
ALOGI("Registering as service...");
service->registerAsService();
我們看下 VehicleHalManager的定義:
class VehicleHalManager : public IVehicle
VehicleHalManager類是由 IVehicle類派生出來,而IVehicle則是從我們上面介紹的.hal檔案裡編譯出來的。
我們繼續來看下下面這句:
service->registerAsService();
我們從.hal檔案編譯出來的.cpp檔案來看下,這個中間生成的cpp檔案所在目錄為:out/soong/.intermediates/hardware/interfaces/automotive/vehicle/2.0/[email protected]_genc++/gen/android/hardware/automotive/vehicle/2.0/VehicleAll.cpp
該函式的具體實現為:
::android::status_t IVehicle::registerAsService(const std::string &serviceName) {
::android::hardware::details::onRegistration("[email protected]", "IVehicle", serviceName);
const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm
= ::android::hardware::defaultServiceManager();
// 獲取到預設的service manager,非常類似於 Binder機制中。有時間的話可以深入研究下。
if (sm == nullptr) {
return ::android::INVALID_OPERATION;
}
::android::hardware::Return<bool> ret = sm->add(serviceName.c_str(), this);
//往service manager 中新增service, 跟Binder機制也是一樣一樣的。
return ret.isOk() && ret ? ::android::OK : ::android::UNKNOWN_ERROR;
}
但是比較奇怪的是add 進去是this 指標,也就是應該是 IVehicle物件,也就是VehicleHalManager的物件。不應該是Bnxxxx的物件麼????我這裡有一臉懵逼。這是第一個懵點,第二個懵點則來的更加不可思議:
const char* IVehicle::descriptor("andro[email protected]::IVehicle");
__attribute__((constructor))static void static_constructor() {
::android::hardware::details::gBnConstructorMap.set(IVehicle::descriptor,
[](void *iIntf) -> ::android::sp<::android::hardware::IBinder> {
return new BnHwVehicle(static_cast<IVehicle *>(iIntf));
});
::android::hardware::details::gBsConstructorMap.set(IVehicle::descriptor,
[](void *iIntf) -> ::android::sp<::android::hidl::base::V1_0::IBase> {
return new BsVehicle(static_cast<IVehicle *>(iIntf));
});
};
我們來看看這段程式碼,首先attribute((constructor))也是gcc 的一個機制,大致意思是在main函式被呼叫之前 static_constructor函式會被呼叫。
::android::hardware::details::gBnConstructorMap.set(IVehicle::descriptor,
[](void *iIntf) -> ::android::sp<::android::hardware::IBinder> {
return new BnHwVehicle(static_cast<IVehicle *>(iIntf));
});
這段程式碼意思是指在 gBnConstructorMap中插入一個key/value,這個value 值是
[](void *iIntf) -> ::android::sp<::android::hardware::IBinder> {
return new BnHwVehicle(static_cast<IVehicle *>(iIntf));
}
這又是什麼鬼啊???搜了下應該是拉曼達表示式,但是懵點是 void *iIntf 這個是引數,這個引數是怎麼傳遞進來的?我都搜了半天都沒找到引數怎麼傳遞進來的。但是看了下BnHwVehicle這個類的定義,明顯是使用了 IVehicle類。
BnHwVehicle::BnHwVehicle(const ::android::sp<IVehicle> &_hidl_impl)
: ::android::hidl::base::V1_0::BnHwBase(_hidl_impl, "[email protected]", "IVehicle") {
_hidl_mImpl = _hidl_impl;
auto prio = ::android::hardware::details::gServicePrioMap.get(_hidl_impl, {SCHED_NORMAL, 0});
mSchedPolicy = prio.sched_policy;
mSchedPriority = prio.prio;
}
::android::status_t BnHwVehicle::onTransact(
uint32_t _hidl_code,
const ::android::hardware::Parcel &_hidl_data,
::android::hardware::Parcel *_hidl_reply,
uint32_t _hidl_flags,
TransactCallback _hidl_cb) {
::android::status_t _hidl_err = ::android::OK;
switch (_hidl_code) {
case 1 /* getAllPropConfigs */:
{
if (!_hidl_data.enforceInterface(IVehicle::descriptor)) {
_hidl_err = ::android::BAD_TYPE;
break;
}
…………………
………………...
bool _hidl_callbackCalled = false;
_hidl_mImpl->getAllPropConfigs([&](const auto &_hidl_out_propConfigs) {
…………………….
…………………...
break;
}
從BnHwVehicle這個類來看,它確實承擔的是HIDL Service的工作,從BnHwVehicle裡會來呼叫IVehicle類,IVehicle類會被繼承成為真正的實現操作類。這個懵點2,到目前還沒有找到怎麼解決點。
到這裡,我們來簡單總結service端:
1) 從Ixxxx類中會派生出新的類,這個類會作為真正的操作類。
2) 從Ixxxx類的派生類中呼叫 registerAsService 去把自己註冊進hw service manager中。
3) 目前看起來,如果有client 發出請求的話,BnXXXXX會相應,BnXXXXX會呼叫自己的Ixxxx的實現函式來完成某一個操作請求。
1) Android Vehicle HAL Client 端使用:
這個Client端存在Android Framework的Car Service當中
在onCreate 函式當中:
“`
@Override
public void onCreate() {
Log.i(CarLog.TAG_SERVICE, “Service onCreate”);
mCanBusErrorNotifier = new CanBusErrorNotifier(this /* context */);
mVehicle = getVehicle(null /* Any Vehicle HAL interface name */);
if (mVehicle == null) {
throw new IllegalStateException("Vehicle HAL service is not available.");
}
try {
mVehicleInterfaceName = mVehicle.interfaceDescriptor();
} catch (RemoteException e) {
throw new IllegalStateException("Unable to get Vehicle HAL interface descriptor", e);
}
Log.i(CarLog.TAG_SERVICE, "Connected to " + mVehicleInterfaceName);
mICarImpl = new ICarImpl(this, mVehicle, SystemInterface.getDefault(this),
mCanBusErrorNotifier);
mICarImpl.init();
SystemProperties.set("boot.car_service_created", "1");
linkToDeath(mVehicle, mVehicleDeathRecipient);
super.onCreate();
}
mVehicle = getVehicle(null /* Any Vehicle HAL interface name */);
獲取到Vehicle HAL.
@Nullable
private static IVehicle getVehicle(@Nullable String interfaceName) {
try {
boolean anyVersion = interfaceName == null || interfaceName.isEmpty();
IVehicle vehicle = null;
if (ENABLE_VEHICLE_HAL_V2_1 && (anyVersion || IVHAL_21.equals(interfaceName))) {
vehicle = android.hardware.automotive.vehicle.V2_1.IVehicle
.getService();
}
if (vehicle == null && (anyVersion || IVHAL_20.equals(interfaceName))) {
vehicle = android.hardware.automotive.vehicle.V2_0.IVehicle
.getService();
}
return vehicle;
} catch (RemoteException e) {
Log.e(CarLog.TAG_SERVICE, "Failed to get IVehicle service", e);
} catch (NoSuchElementException e) {
Log.e(CarLog.TAG_SERVICE, "IVehicle service not registered yet");
}
return null;
}
理論上拿到IVehicle vehicle 物件後,就應該能夠來做對Vehicle HAL做相關呼叫了。這一部分就先到這裡完結吧。
相關推薦
Android O 前期預研之三:Android Vehicle HAL
Android Automotive Android Automotive 是Android Oreo中的一個新的特色功能,從AOSP的程式碼上來看,Android O中已經包含有了從Application到Framework 到HAL的整體框架,這一章節,我
android中的對話方塊之三:自定義對話方塊
首先看下效果圖 下面講一下具體的實現: 1.修改系統預設的Dialog樣式(風格、主題) 2.自定義Dialog佈局檔案 3.可以自己封裝一個類,繼承自Dialog或者直接使用Dialog類來實現,為了方便以後重複使用,建議自己封裝一個Dialog類 ==
Android電源管理之三:PowerManager.WakeLock原始碼詳讀
PowerManager.WakeLock 有加鎖和解鎖兩種狀態,加鎖的方式有兩種,一種是永久的鎖,這樣的鎖除非顯式的放開,是不會解鎖的,所以這種鎖用起來要非常的小心。第二種鎖是超時鎖,這種鎖會在鎖住後一段時間自動解鎖。 在建立了PowerManager.W
Android問題集錦轉載之三:Javah 常見錯誤記錄-NDK與JNI除錯
測試檔案:hello-jni/src/com/example/hellojni/HelloJni.java/** * 該檔案來自 Android NDK Sample - HelloJni, 為了便於說明問題,我作了一些修改。 */ package com.example
Android系統資訊獲取 之三:IMSI號和IMEI解釋
IMSI號: IMSI是國際移動使用者識別碼的簡稱(International Mobile Subscriber Identity) 它是在公眾陸地行動電話網(PLMN)中用於唯一識別移動使用者的一個號碼。在GSM網路,這個號碼通常被存放在SIM卡中 IMSI共有15位,其結構如下: MCC
ANDROID音訊系統散記之三:resample-2
這篇是承接上一篇提到的底層resample處理,以Samsung的tiny alsa-lib為例說明。 tiny alsa-lib 這個tiny alsa-lib位於android2.3.1-gingerbread/device/samsung/crespo/libau
Android系統應用---SystemUI之三:狀態列電池圖示的顯示和Android電池管理的探討
電池圖示顯示 電池圖示是SystemUI顯示中不可缺少的一部分,它顯示在SystemUI的電池和訊號組合區域。 從佈局來看,電池的顯示屬於status_bar.xml,包含了system_icons.xml佈局 <includelayout="@layout/
android Service之三:傳遞基本型資料的遠端服務
讓其他應用程式複用本程式的服務。這樣的服務叫遠端(remote)服務,實際上是程序間通訊(RPC)。 如果是呼叫不需要資料互動的遠端服務(startservice呼叫),跟無需資料互動的我本地服務呼叫是類似的 如果呼叫遠端服務進行資料互動,這時需要使用android
VCSA 6.5 HA配置 之三 :準備工作
vmware vcenter ha 高可用 vcsa 接著上一篇文章部署完成VCSA 6.5後,還需要做一些準備工作才能開啟高可用功能,本篇文章主要就講述如何為vCenter 高可用進行準備工作配置vCenter HA網絡從vCenter HA的架構圖中可以看出對於vCenter HA的高
Linux學習之三:文件夾系統的結構和相對(絕對)路徑
sharp 二進制 沒有 數據 csharp pan 用戶 ont 臨時 理解每個目錄的作用 bin 二進制文件 boot 系統的啟動文件、內核 dev 設備文件 etc 配置文件 home 用戶的家目錄 lib 鏈接庫文件 l
RabbitMQ系列教程之三:發布/訂閱(Publish/Subscribe)
mqc 標題 整合 參數 cti 事情 return 控制臺 run (本教程是使用Net客戶端,也就是針對微軟技術平臺的) 在前一個教程中,我們創建了一個工作隊列。工作隊列背後的假設是每個任務會被交付給一個【工人】。在這一部分我們將做一些完全不同的事情--我們將向多個
OSPF詳解之三:OSPF LSA詳解
ospf lsa詳解 forwarding address OSPF LSA詳解OSPF V2版本中常用的主要有6類LSA,分別是Router-LSA、Network-LSA、Network-summary-LSA、ASBR-summary-LSA、AS-External-LSA、NSSA-LSA,接
Django運維後臺的搭建之三:用url去精細定制與反向解析
django 反向解析 參數傳遞 url指向 上一篇文章裏,我們做了一個alionlineecs(阿裏雲線上環境服務器)的添加界面,但是要知道我們的計劃裏是有六個分支的,而alionlineecs僅僅是其中之一,要是每一個都這麽寫的話,那麽views.py肯定又臭又長,充滿了大量的復制片段。對
camera攝像原理之三:色溫和自動白平衡【轉】
mil gho 實現 技術分享 處理 目標 紅旗 適應 如果 轉自:http://blog.csdn.net/ghostyu/article/details/7912863 色溫的定義:將黑體從絕對零度開始加溫,溫度每升高一度稱為1開氏度(用字母K表示),當溫度升高到一定
Halcon學習之三:有關圖像通道的函數
spa com detail too pan targe 個數 word pop 黑白攝像機會返回每個像素所對應的能量采用結果,這些結果組成了一幅單通道灰度值圖像,而對於RGB彩色攝像機,它將返回每個像素所對應的三個采樣結果,也就是一幅三通道圖像。下面這些是與圖像通道有關的
SoC嵌入式軟件架構設計之三:代碼分塊(Bank)設計原則
post 介紹 讀寫 cor 層次 clas rom bank 分配 上一節講述了在沒有MMU的CPU(如80251、MIPS M控制器系列、ARM cortex m系列)上實現虛擬內存管理的集成硬件設計方法。新設計的內存管理管理單元要實現虛擬內存管理還須要
初識Redis系列之三:Redis支持的數據類型及使用
ted print 數據類型 eight 排序 sorted ring hang 無序 支持的數據類型有五種: string(字符串)、hash(哈希)、list(列表)、set(集合)及zset(sorted set:有序集合); 下面分別對這幾種類型進行簡單的Redis
緩存系列之三:redis安裝及基本數據類型命令使用
pytho children tile 指令 sed eject 檢測 install 文件的 一:Redis是一個開源的key-value存儲系統。與Memcached類似,Redis將大部分數據存儲在內存中,支持的數據類型包括:字符串、哈希表、鏈表、集合、有序集合以及基
SIPp常用腳本之三:UAC
pause rep iso sof app peer ati test level UAC是作為SIP消息的發起端,可以控制消息速率什麽的,方便極了。 一、uac.xml <?xml version="1.0" encoding="ISO-8859-1" ?>
測試開發linux面試之三:後臺進程之操作
狀態 很好 分配 例如 名稱 標識 批處理 推薦 子進程 Hi,大家好我是Tom,繼上次分享之後這次給大家帶來新的知識。 進程是Linux系統中一個非常重要的概念。Linux是一個多任務的操作系統,系統上經常同時運行著多個進程。我們不關心這些進程究竟是如何分配的,或者是內核