前の章では、JNIを使用してAndroidアプリケーションレイヤーアプリ操作ノードを実装する方法について説明しました:https://blog.csdn.net/weixin_41486477/article/details/110791176
前の章では、CTS認定が必要な場合はJNIメソッドを使用できないと述べたため、この章では、Androidアプリケーションレイヤーアプリ操作ノードを実装するためのHidlを構築する方法を整理します。
driverとhal(testgpio.default.so)の部分は、JNI実装の部分と同等です。以下では、hidlを構築し、フレームワークで呼び出す方法に焦点を当てます。
1.hidlをビルドします
新しいhardware \ interfaces \ testgpio \ 1.0 \ ITestgpio.halを作成し、generateはint32_tタイプなどの生成された関数タイプを表します。
package [email protected];
interface Itestgpio {
set_gpio_up(int32_t gpio_index) generates (int32_t result);
set_gpio_down(int32_t gpio_index) generates (int32_t result);
testgpio_open()generates (int32_t result);
};
hidl-genツールを使用してカタログファイルを生成します。
1.执行make hidl-gen 先安装工具
2.依次执行
export [email protected]
export LOC=hardware/interfaces/testgpio/1.0/default/
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
./hardware/interfaces/update-makefiles.sh
生成されたファイルは単なるテンプレートであり、必要に応じて変更する必要があります
修改ハードウェア\ interfaces \ testgpio \ 1.0 \ default \ Testgpio.h
#ifndef ANDROID_HARDWARE_TESTGPIO_V1_0_TESTGPIO_H
#define ANDROID_HARDWARE_TESTGPIO_V1_0_TESTGPIO_H
#include <android/hardware/testgpio/1.0/ITestgpio.h>
#include <hidl/MQDescriptor.h>
#include <hardware/hardware.h>
#include <hidl/Status.h>
#include "hardware/testgpio.h"
namespace android {
namespace hardware {
namespace testgpio {
namespace V1_0 {
namespace implementation {
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
struct Testgpio : public ITestgpio {
Testgpio();
~Testgpio();
// Methods from ::android::hardware::testgpio::V1_0::ITestgpio follow.
Return<int32_t> set_gpio_up(int32_t gpio_index) override;
Return<int32_t> set_gpio_down(int32_t gpio_index) override;
Return<int32_t> testgpio_open() override;
private:
int openHal();
testgpio_device_t *mDevice;
int ret;
// Methods from ::android::hidl::base::V1_0::IBase follow.
};
// FIXME: most likely delete, this is only for passthrough implementations
// extern "C" ITestgpio* HIDL_FETCH_ITestgpio(const char* name);
} // namespace implementation
} // namespace V1_0
} // namespace testgpio
} // namespace hardware
} // namespace android
#endif
hardware \ interfaces \ testgpio \ 1.0 \ default \ Testgpio.cppを変更します
#include "Testgpio.h"
#include <utils/Log.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "Testgpio.h"
namespace android {
namespace hardware {
namespace testgpio {
namespace V1_0 {
namespace implementation {
static testgpio_device_t* testgpio_device;
// Methods from ::android::hardware::testgpio::V1_0::ITestgpio follow.
Testgpio::Testgpio() {
//sInstance = this; // keep track of the most recent instance
ret = openHal();
if (!ret) {
ALOGE("Can't open HAL module");
}
}
Testgpio::~Testgpio() {
ALOGV("~Testgpio()");
if (mDevice == nullptr) {
ALOGE("No valid device");
return;
}
int err;
if (0 != (err = mDevice->common.close(
reinterpret_cast<hw_device_t*>(mDevice)))) {
ALOGE("Can't close fingerprint module, error: %d", err);
return;
}
mDevice = nullptr;
}
Return<int32_t> Testgpio::set_gpio_up(int32_t gpio_index) {
// TODO implement
return testgpio_device->set_gpio_up(testgpio_device,gpio_index);
}
Return<int32_t> Testgpio::set_gpio_down(int32_t gpio_index) {
// TODO implement
return testgpio_device->set_gpio_down(testgpio_device,gpio_index);
}
Return<int32_t> Testgpio::testgpio_open() {
// TODO implement
return testgpio_device->testgpio_open(testgpio_device);
}
int Testgpio::openHal() {
int err;
hw_module_t* module;
hw_device_t* device;
ALOGE("testgpio,native testgpioOpen ...");
/* 1. hw_get_module */
err = hw_get_module(TESTGPIO_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
/* 2. get device : module->methods->open */
err = module->methods->open(module, NULL, &device);
if (err == 0) {
/* 3. call testgpio_open */
testgpio_device = (testgpio_device_t *)device;
return testgpio_device->testgpio_open(testgpio_device);
} else {
ALOGE("testgpio,open faitestgpio ...");
return -1;
}
}else{
ALOGE("testgpio,get_module faitestgpio ...");
}
return -1;
}
// Methods from ::android::hidl::base::V1_0::IBase follow.
//ITestgpio* HIDL_FETCH_ITestgpio(const char* /* name */) {
//return new Testgpio();
//}
//
} // namespace implementation
} // namespace V1_0
} // namespace testgpio
} // namespace hardware
} // namespace android
追加ハードウェア\ interfaces \ testgpio \ 1.0 \ default \ service.cpp
#define LOG_TAG "[email protected]"
#include <android/log.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
#include <android/hardware/testgpio/1.0/ITestgpio.h>
#include "Testgpio.h"
using android::hardware::testgpio::V1_0::ITestgpio;
using android::hardware::testgpio::V1_0::implementation::Testgpio;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::sp;
int main() {
sp<ITestgpio> service = new Testgpio();
configureRpcThreadpool(1, true /*callerWillJoin*/);
if (::android::OK != service->registerAsService()) {
return 1;
}
joinRpcThreadpool();
return 0; // should never get here
}
rcファイルhardware \ interfaces \ testgpio \ 1.0 \ default \ [email protected]を追加します
service vendor.testgpio_hal /vendor/bin/hw/[email protected]
# "class hal" causes a race condition on some devices due to files created
# in /data. As a workaround, postpone startup until later in boot once
# /data is mounted.
class late_start
user system
group system input
writepid /dev/cpuset/system-background/tasks
Hardware \ interfaces \ testgpio \ 1.0 \ default \ Android.bp
cc_binary {
name: "[email protected]",
defaults: ["hidl_defaults"],
init_rc: ["[email protected]"],
vendor: true,
relative_install_path: "hw",
// FIXME: this should be 'vendor: true' for modules that will eventually be
// on AOSP.
proprietary: true,
srcs: [
"Testgpio.cpp",
"service.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"libcutils",
"liblog",
"libhidlbase",
"libhardware",
"[email protected]",
],
}
Hardware \ interfaces \ testgpio \ 1.0 \ Android.bp
// This file is autogenerated by hidl-gen -Landroidbp.
hidl_interface {
name: "[email protected]",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"ITestgpio.hal",
],
interfaces: [
"[email protected]",
],
gen_java: true,
}
hardware \ interfaces \ testgpio \ 1.0 \ディレクトリに入り、mmaを実行し、生成する必要があります
out \ target \ product \ XXXXXX \ vendor \ bin \ hw \ android.hardware.testgpio @ 1.0-service
out \ target \ product \ XXXXXX \ vendor \ lib(64)\ hw \ android.hardware.testgpio @ 1.0-service.so
rcファイルは、copy_fileを使用してコンパイルに含めることができます。
フレームワークの呼び出し方
主な変更点はframeworks \ base \ services \ core \ java \ com \ android \ server \ TestgpioService.javaにあります
package com.android.server;
import android.util.Config;
import android.util.Log;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.hardware.testgpio.V1_0.ITestgpio; //引入hidl的包
import android.hardware.testgpio.ITestgpioService;
public final class TestgpioService extends ITestgpioService.Stub {
private String TAG = "TestgpioService";
private ITestgpio mDaemon;
public TestgpioService(Context context){
try {
mDaemon = ITestgpio.getService(true);//get service,参数必须为true,不然获取不到
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public int setUp(int gpio_index){
Log.i("TestgpioPlatform", "Testgpio Up");
try{
mDaemon.set_gpio_up(gpio_index);
} catch (RemoteException e) {
e.printStackTrace();
}
return 0;
}
public int setDown(int gpio_index){
Log.i("TestgpioPlatform", "Testgpio Down");
try{
mDaemon.set_gpio_down(gpio_index);
} catch (RemoteException e) {
e.printStackTrace();
}
return 0;
}
}
在フレームワーク/ベース/サービス/コア/Android.bp
@@ -44,6 +44,7 @@ java_library_static {
"android.hardware.vibrator-V1.0-java",
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
+ "android.hardware.testgpio-V1.0-java", //引用hidl库
"vendor.qti.hardware.servicetracker-V1.0-java",
],
}
3.その他の構成
1.manifest.xmlを構成します。合計で3つの場所があります。MTKプラットフォームは2つである必要があります
device/qcom/product/manifest.xml
<hal format="hidl">
<name>android.hardware.testgpio</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>ITestgpio</name>
<instance>default</instance>
</interface>
</hal>
device/qcom/common/vendor_framework_compatibility_matrix.xml
<hal format="hidl" optional="true">
<name>android.hardware.testgpio</name>
<version>1.0</version>
<interface>
<name>ITestgpio</name>
<instance>default</instance>
</interface>
</hal>
hardware/interfaces/compatibility_matrices/compatibility_matrix.1.xml
<hal format="hidl" optional="true">
<name>android.hardware.testgpio</name>
<version>1.0</version>
<interface>
<name>ITestgpio</name>
<instance>default</instance>
</interface>
</hal>
2.hidlを追加した後
分别在
build/make/target/product/vndk/28.txt
build/make/target/product/vndk/current.txt
严格按照字母排列顺序添加:
VNDK-core: [email protected]
4.デバッグ中に発生した問題
1.StartServiceが失敗する
12-09 08:27:19.285 1252 1252 I SystemServer: StartTestgpioService
12-09 08:27:19.290 1252 1252 E SystemServer: Failure starting TestgpioService
12-09 08:27:19.290 1252 1252 E SystemServer: java.util.NoSuchElementException
12-09 08:27:19.290 1252 1252 E SystemServer: at android.os.HwBinder.getService(Native Method)
12-09 08:27:19.290 1252 1252 E SystemServer: at android.os.HwBinder.getService(HwBinder.java:91)
12-09 08:27:19.290 1252 1252 E SystemServer: at android.hardware.testgpio.V1_0.ITestgpio.getService(ITestgpio.java:48)
12-09 08:27:19.290 1252 1252 E SystemServer: at android.hardware.testgpio.V1_0.ITestgpio.getService(ITestgpio.java:52)
12-09 08:27:19.290 1252 1252 E SystemServer: at com.android.server.TestgpioService.<init>(TestgpioService.java:19)
12-09 08:27:19.290 1252 1252 E SystemServer: at com.android.server.SystemServer.startOtherServices(SystemServer.java:1377)
12-09 08:27:19.290 1252 1252 E SystemServer: at com.android.server.SystemServer.run(SystemServer.java:443)
12-09 08:27:19.290 1252 1252 E SystemServer: at com.android.server.SystemServer.main(SystemServer.java:302)
12-09 08:27:19.290 1252 1252 E SystemServer: at java.lang.reflect.Method.invoke(Native Method)
12-09 08:27:19.290 1252 1252 E SystemServer: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
12-09 08:27:19.290 1252 1252 E SystemServer: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:838)
12-09 08:27:19.290 1252 1252 D SystemServerTiming: StartTestgpioService took to complete: 5ms
TestgpioService.java、mDaemon = ITestgpio.getService(true); // get serviceでは、パラメーターはtrueである必要があります。そうでない場合、取得できません。
2. [email protected]サービスは、起動後に自動的に開始できません
最初にadbシェルで次のコマンドを実行して、サービスを手動で開始し、最初に機能を確認できます。
cd vendor/bin/hw
./[email protected] &
binサービスのseラベルを構成します。seliunxパーミッションがオフになっている場合でも、ラベルが構成されている限り、selinuxパーミッションがオフになっていると、他のselinuxパーミッションをデバッグできます。
diff --git a/device/qcom/sepolicy/private/file_contexts b/device/qcom/sepolicy/private/file_contexts
index 1c3e9eb..7cdda39 100755
--- a/device/qcom/sepolicy/private/file_contexts
+++ b/device/qcom/sepolicy/private/file_contexts
@@ -74,3 +74,4 @@
/data/dpm(/.*)? u:object_r:dpmd_data_file:s0
/data/misc/qvr(/.*)? u:object_r:qvrd_data_file:s0
/data/misc/mirrorlinkserver(/.*)? u:object_r:mirrorlink_data_file:s0
+/(vendor|system/vendor)/bin/hw/android\.hardware\.testgpio@1\.0-service u:object_r:hal_testgpio_exec:s0
新增 /device/qcom/sepolicy/private/hal_testgpio.te
@@ -0,0 +1,5 @@
+type hal_testgpio, domain;
+hal_server_domain(hal_testgpio, hal_fingerprint)//这里hal_fingerprint是我为了快速调试,随便加的系统中已经有的,改成自己的
+
+type hal_testgpio_exec, exec_type, vendor_file_type, file_type;
+init_daemon_domain(hal_testgpio)
3.コンパイル時のエラー:VNDKライブラリリストが変更されました
a.使用 diff 比较 build\make\target\product\vndk\28.txt 和 current.txt 两个文件是否相同,如果不相同,请修改至相同。
b.如果上面两个文件相同,但是仍然报错的话。请查看out/target/product/product_name/obj/PACKAGING/vndk_intermediates/libs.txt文件与上面两个文件是否相同。
如果libs.txt文件与current.txt不相同的话,可能你修改了hardware/interfaces/**/*.bp文件,使用git status查看。
结论:必须保证28.txt、current.txt和 libs.txt 是相同的,如果不相同,则会编译出错。
4.openHalはできません
添加构造函数,调用openHal
Testgpio::Testgpio() {
//sInstance = this; // keep track of the most recent instance
ret = openHal();
if (!ret) {
ALOGE("Can't open HAL module");
}
}