HIDLの実装-Androidアプリケーションレイヤーアプリ操作ノード(例としてgpioを取り上げます)

前の章では、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");
    }
}

 

おすすめ

転載: blog.csdn.net/weixin_41486477/article/details/110948162