Android C++服务创建和HIDL的生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


Android C++服务创建和HIDL的生成

总结c++创建服务和HIDL生成的一些步骤,本文未使用指令去生成创建hidl和对应的服务文件。

一、HIDL的生成

1.首先,在vendor/mediatek/proprietary/hardware/interfaces中创建文件夹testofhidl/1.0,
在上述的路径中,即…/interfaces,主要是mediatek存放HAL文件的地方,注意,在里面一般也有如下两个文件updat-hash.sh和updat-makefiles.sh,创建完成后,我们有如下路径:
vendor/mediatek/proprietary/hardware/interfaces/testofhidl/1.0

2.在testofhidl/1.0/下创建文件ITestOfHidl.hal和IDataCallback.hal,两者都是Hal文件,IDataCallback.hal是做回调用的,最后创建Android.bp文件,它们都是在…/testofhidl/1.0这个目录下的,它们的分别如下
ITestOfHidl.hal

package vendor.mediatek.hardware.testofhidl@1.0;

import vendor.mediatek.hardware.testofhidl@1.0::IDataCallback;

interface ITestOfHidl {
   init();
   release();
   sendData(vec<uint8_t> data);
   setDataCallback(IDataCallback callback) generates (uint32_t channel);
};

IDataCallback.hal

package vendor.mediatek.hardware.testofhidl@1.0;

interface IDataCallback {
    onDataReceived(vec<uint8_t> data);
};

Android.bp

// This file is autogenerated by hidl-gen -Landroidbp.

hidl_interface {
    name: "vendor.mediatek.hardware.testofhidl@1.0",
    root: "vendor.mediatek.hardware",
    srcs: [
        "IDataCallback.hal",
        "ITestOfHidl.hal",
    ],
    interfaces: [
        "android.hidl.base@1.0",
    ],
    gen_java: true,
}
subdirs = [
    "default",
]

在…/testofhidl文件夹下也创建一个Android.bp文件

// This is an autogenerated file, do not edit.
subdirs = [
    "1.0",
]

最后,使用vendor/mediatek/proprietary/hardware/interfaces中的updata-hash.sh增加一下current.txt的哈希值,可以看到current.txt多出这两行

af1b12d5eaba28900257dd15689aca72ee6badef0469fa73cb92893c2a416d80 vendor.mediatek.hardware.testofhidl@1.0::IDataCallback
7b3b7f0d9ba0833e46e368655e7add4a79c23979ae9f57139519e589f8ba4606 vendor.mediatek.hardware.testofhidl@1.0::ITestOfHidl

注意:如果没有updata-hash.sh这个脚本,可以参考https://blog.csdn.net/kehyuanyu/article/details/120904314?spm=1001.2014.3001.5502,里面有教你如何使用hild-gen生成hash的方法。
编译通过,以上就算完成了。

二、c++服务的创建

在vendor/mediatek/proprietary/hardware/interfaces/testofhidl/1.0/default/创建如下:
Android.bp

// FIXME: your file license if you have one

cc_binary {
    name: "vendor.mediatek.hardware.testofhidl@1.0-service",
    relative_install_path: "hw",
    proprietary: true,
    vendor: true,
    defaults: ["hidl_defaults"],
    init_rc: ["vendor.mediatek.hardware.testofhidl@1.0-service.rc"],
    srcs: [
        "TestOfHidl.cpp",
        "service.cpp"
    ],
    shared_libs: [
        "liblog",
        "libcutils",
        "libdl",
        "libbase",
        "libutils",
        "libhardware",
        "libhidlbase",
        "vendor.mediatek.hardware.testofhidl@1.0",
    ],
}

TestOfHidl.cpp

// FIXME: your file license if you have one
#define TAG "testofhidl-1.0-service"

#include "TestOfHidl.h"

namespace vendor::mediatek::hardware::testofhidl::implementation {

// Methods from ::vendor::mediatek::hardware::testofhidl::V1_0::ITestOfHidl follow.
Return<void> TestOfHidl::init() {
    // TODO implement
    
	std::thread th(&TestOfHidl::myLoop, this);
	if(th.joinable()){
		th.detach();
	}
		
    return Void();
}

void TestOfHidl::myLoop()
{
    while(true){
        if(!deqIn.empty()){
            char *p = deqIn.front();
            std::vector<uint8_t> out;
            //对通过client中使用sendData()传进来的byte进行修改
            //byte[] p = {}的第二位固定为1
            p[1] = 1;
            covertArray2Vector(p, 6, out);
            mCallback->onDataReceived(out);
            deqIn.pop_front();
        }
    }
}

Return<void> TestOfHidl::release() {
    // TODO implement
    return Void();
}

void TestOfHidl::covertVector2Array(std::vector<uint8_t> in, char *out)
{
    int size = in.size();
    for (int i = 0; i < size; i++)
    {
        out[i] = in.at(i);
    }
}

void TestOfHidl::covertArray2Vector(const char *in, int len, std::vector<uint8_t> &out)
{
    out.clear();
    for (int i = 0; i < len; i++)
    {
        out.push_back(in[i]);
    }
}

Return<void> TestOfHidl::sendData(const hidl_vec<uint8_t>& data) {
    // TODO implement

    char *cstr_data = new char[data.size() + 1];
    covertVector2Array(data, cstr_data);
    deqIn.push_back(cstr_data);

    return Void();
}

TestOfHidl::TestOfHidl(): callback_map({}), mChd(this){}

Return<void> TestOfHidl::setDataCallback(const sp<::vendor::mediatek::hardware::testofhidl::V1_0::IDataCallback>& callback) {
    // TODO implement
    channel_id++;
    mCallback = callback;
    if (mChd != nullptr) {
        LOGD("linkToDeath\n");
        callback->linkToDeath(mChd, channel_id);
    } else {
        LOGE("mChd is null\n");
    }    
    return channel_id;
}

void TestOfHidl::serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
    LOGE("client is crash, channel_id = %lu!!!", cookie);
    int count = callback_map.erase(cookie);
    if(count == 1){
        callback_interface_usage[cookie] = false;
    }else if(count > 1){
        LOGE("error callback_map, please check callback_map !!!");
    }
}


// Methods from ::android::hidl::base::V1_0::IBase follow.

//ITestOfHidl* HIDL_FETCH_ITestOfHidl(const char* /* name */) {
    //return new TestOfHidl();
//}
//
}  // namespace vendor::mediatek::hardware::testofhidl::implementation

TestOfHidl.h

// FIXME: your file license if you have one

#pragma once

#include <vendor/mediatek/hardware/testofhidl/1.0/ITestOfHidl.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <android/log.h>
#include <thread>
#include <deque>


namespace vendor::mediatek::hardware::testofhidl::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;

#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) 
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , TAG, __VA_ARGS__)


struct TestOfHidl : public V1_0::ITestOfHidl, android::hardware::hidl_death_recipient {
    // Methods from ::vendor::mediatek::hardware::testofhidl::V1_0::ITestOfHidl follow.
    Return<void> init() override;
    Return<void> release() override;
    Return<void> sendData(const hidl_vec<uint8_t>& data) override;
    Return<uint32_t> setDataCallback(const sp<::vendor::mediatek::hardware::testofhidl::V1_0::IDataCallback>& callback) override;
	void serviceDied(uint64_t cookie, const android::wp<::android::hidl::base::V1_0::IBase>& who) override;
    // Methods from ::android::hidl::base::V1_0::IBase follow.
private:
    sp<V1_0::IDataCallback> mCallback = nullptr;
    ::android::sp<hidl_death_recipient> mChd;
    
    uint32_t channel_id = 0;
    std::deque<char*> deqIn;
    void myLoop();
    void covertArray2Vector(const char *in, int len, std::vector<uint8_t> &out);
    void covertVector2Array(std::vector<uint8_t> in, char *out);
public:
	TestOfHidl();
};

// FIXME: most likely delete, this is only for passthrough implementations
// extern "C" ITestOfHidl* HIDL_FETCH_ITestOfHidl(const char* name);

}  // namespace vendor::mediatek::hardware::testofhidl::implementation

上述文件,通过hidl-gen生成,然后再自己修改部分内容。
vendor.mediatek.hardware.testofhidl@1.0-service.rc

service testofhidl-hal-1-0 /vendor/bin/hw/vendor.mediatek.hardware.testofhidl@1.0-service
    class hal
    user root
    group system

service.cpp

#define TAG "testofhidl-1.0-service"
 
#include <android/log.h>
#include <hidl/HidlTransportSupport.h>
#include <vendor/mediatek/hardware/testofhidl/1.0/ITestOfHidl.h>
#include <hidl/LegacySupport.h>
#include "TestOfHidl.h"

using android::sp;
using android::status_t;
using android::OK;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::defaultPassthroughServiceImplementation;
using vendor::mediatek::hardware::testofhidl::V1_0::ITestOfHidl;
using vendor::mediatek::hardware::testofhidl::implementation::TestOfHidl;


int main()
{
    //LOGD("testofhidl server0.");
    android::sp<ITestOfHidl> service = new TestOfHidl();
    //LOGD("testofhidl server1.");

    configureRpcThreadpool(4, true /*callerWillJoin*/);
    status_t status = service->registerAsService();

    if (status == OK)
    {   
        //LOGD("testofhidl HAL Ready0.");
        service->init();
        //LOGD("testofhidl HAL Ready1.");
        joinRpcThreadpool();
        //LOGD("testofhidl HAL Ready2.");
    }

    LOGD("Cannot register testofhidl HAL service");
    return 1;
}

三、有关/device内的部分文件修改

device/mediatek/mt_xxxx/device.mk添加如下

...
PRODUCT_PACKAGES += vendor.mediatek.hardware.testofhidl@1.0-service
PRODUCT_PACKAGES += vendor.mediatek.hardware.testofhidl@1.0
...

device/mediatek/mt_xxxx/manifest.xml添加如下

    <hal format="hidl">
        <name>vendor.mediatek.hardware.testofhidl</name>
        <transport>hwbinder</transport>
        <version>1.0</version>
        <interface>
            <name>ITestOfHidl</name>
            <instance>default</instance>
        </interface>
    </hal>

在添加了这一部分内容后,可能会报一个兼容性矩阵相关的错误(FAILED: out/target/product/T9530_Base_TP_VASA/obj/PACKAGING/check_vintf_all_intermediates/check_vintf_compatible_log),官方推荐的解决方法如下:

1. Update deprecated HALs to the latest version.
2. Check for any typos in device manifest or framework compatibility matrices with FCM version >= 5 
3. For new platform HALs, add them to any framework compatibility matrix with FCM version >= 5 where applicable.
4. For device-specific HALs, add to DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE or DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE.: Success INCOMPATIBLE

根据官方推荐的解决方法,我们修改如下文件:
在/hardware/interfaces/compatibility_matricescompatibility_matrix.5.xml中添加如下

    <hal format="hidl" optional="true">
        <name>vendor.mediatek.hardware.testofhidl</name>
        <version>1.0</version>
        <interface>
            <name>ITestOfHidl</name>
            <instance>default</instance>
        </interface>
    </hal>

这部分完成后,也可以成功编译。

四、修改SELINUX相关部分,关乎到service的开机自启动

4-1 system/sepolicy/vendor目录

在/system/sepolicy/vendor/中新建hal_testofhidl_default.te

type hal_testofhidl_default, domain;
hal_server_domain(hal_testofhidl_default, hal_testofhidl)
 
type hal_testofhidl_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_testofhidl_default)

在system/sepolicy/vendor/file_contexts中添加如下

/(vendor|system/vendor)/bin/hw/vendor\.mediatek\.hardware\.testofhidl@1\.0-service     u:object_r:hal_testofhidl_default_exec:s0

4-2 system/sepolicy/public和/system/sepolicy/prebuilts目录

在/system/sepolicy/public/新建hal_testofhidl.te

# HwBinder IPC from client to server, and callbacks
binder_call(hal_testofhidl_client, hal_testofhidl_server)
binder_call(hal_testofhidl_server, hal_testofhidl_client)
 
add_hwservice(hal_testofhidl_server, hal_testofhidl_hwservice)
 
allow hal_testofhidl_client hal_testofhidl_hwservice:hwservice_manager find;

在/system/sepolicy/public/hwservice.te添加如下

type hal_testofhidl_hwservice, hwservice_manager_type;

在system/sepolicy/public/attributes添加如下

hal_attribute(testofhidl);

在/system/sepolicy/prebuilts/api/30.0/public/创建hal_testofhidl.te(同步上方public修改)

# HwBinder IPC from client to server, and callbacks
binder_call(hal_testofhidl_client, hal_testofhidl_server)
binder_call(hal_testofhidl_server, hal_testofhidl_client)
 
add_hwservice(hal_testofhidl_server, hal_testofhidl_hwservice)
 
allow hal_testofhidl_client hal_testofhidl_hwservice:hwservice_manager find;

在system/sepolicy/prebuilts/api/30.0/public/hwservice.te做如下添加(同步上方public修改)

type hal_testofhidl_hwservice, hwservice_manager_type;

在system/sepolicy/prebuilts/api/30.0/public/attributes做如下添加(同步上方public修改)

hal_attribute(testofhidl);

4-3 system/sepolicy/private/和/system/sepolicy/prebuilts目录

在system/sepolicy/private/hwservice_contexts做如下添加

vendor.mediatek.hardware.testofhidl::ITestOfHidl                u:object_r:hal_testofhidl_hwservice:s0

在system/sepolicy/private/compat/26.0/26.0.ignore.cil和
system/sepolicy/private/compat/27.0/27.0.ignore.cil和
system/sepolicy/private/compat/28.0/28.0.ignore.cil和
system/sepolicy/private/compat/29.0/29.0.ignore.cil做如下添加(这个根据自己实际情况添加)

hal_testofhidl_hwservice

在system/sepolicy/prebuilts/api/30.0/private/hwservice_contexts做如下添加

vendor.mediatek.hardware.testofhidl::ITestOfHidl                u:object_r:hal_testofhidl_hwservice:s0

在system/sepolicy/prebuilts/api/30.0/private/compat/26.0/26.0.ignore.cil和
system/sepolicy/prebuilts/api/30.0/private/compat/27.0/27.0.ignore.cil和
system/sepolicy/prebuilts/api/30.0/private/compat/28.0/28.0.ignore.cil和
system/sepolicy/prebuilts/api/30.0/private/compat/29.0/29.0.ignore.cil做如下添加

hal_testofhidl_hwservice

编译后,将固件烧录到板子上,开机后,就可以查看到如下进程了

T9530_Base_TP_VASA:/ $ ps -A | grep testofhidl
system          527      1 10810148  4744 0                   0 R vendor.mediatek.hardware.testofhidl@1.0-service

五、以上创建与修改(增加)的文件记录如下

有如下修改

        modified:   device/mediatek/mt8195/device.mk
        modified:   device/mediatek/mt8195/manifest.xml
        modified:   system/sepolicy/prebuilts/api/30.0/private/compat/26.0/26.0.ignore.cil
        modified:   system/sepolicy/prebuilts/api/30.0/private/compat/27.0/27.0.ignore.cil
        modified:   system/sepolicy/prebuilts/api/30.0/private/compat/28.0/28.0.ignore.cil
        modified:   system/sepolicy/prebuilts/api/30.0/private/compat/29.0/29.0.ignore.cil
        modified:   system/sepolicy/prebuilts/api/30.0/private/hwservice_contexts
        modified:   system/sepolicy/prebuilts/api/30.0/public/attributes
        modified:   system/sepolicy/prebuilts/api/30.0/public/hwservice.te
        modified:   system/sepolicy/private/compat/26.0/26.0.ignore.cil
        modified:   system/sepolicy/private/compat/27.0/27.0.ignore.cil
        modified:   system/sepolicy/private/compat/28.0/28.0.ignore.cil
        modified:   system/sepolicy/private/compat/29.0/29.0.ignore.cil
        modified:   system/sepolicy/private/hwservice_contexts
        modified:   system/sepolicy/public/attributes
        modified:   system/sepolicy/public/hwservice.te
        modified:   system/sepolicy/vendor/file_contexts
        modified:   vendor/mediatek/proprietary/hardware/interfaces/current.txt

有如下创建

        system/sepolicy/prebuilts/api/30.0/public/hal_testofhidl.te
        system/sepolicy/public/hal_testofhidl.te
        system/sepolicy/vendor/hal_testofhidl_default.te
        vendor/mediatek/proprietary/hardware/interfaces/testofhidl/

其中vendor/mediatek/proprietary/hardware/interfaces/testofhidl内包含如下添加

/1.0
	Android.bp
	IDataCallback.hal
	ITestOfHidl.hal
	/default
		Android.bp
		service.cpp
		TestOfHidl.cpp
		TestOfHidl.h
		vendor.mediatek.hardware.testofhidl@1.0-service.rc

六、在AS创建对应的Client

从/out/soong/.intermediates/vendor/mediatek/proprietary/hardware/interfaces/testofhidl/1.0/vendor.mediatek.hardware.testofhidl-V1.0-java/android_common/combined中获取如下包:

vendor.mediatek.hardware.testofhidl-V1.0-java.jar

使用Android Studio,将这个jar包放入app/libs中,右击这个包,点击add as library,build.gradle(Module)的dependencies会自动生成如下:

dependencies {
	...
    implementation files('libs\\vendor.mediatek.hardware.testofhidl-V1.0-java.jar')
    ...
}

从Android的原生代码里,prebuilt/sdk/30/system/获取android.jar,将获取到的jar包,替换掉D:\software\androidSDK\platforms\android-30的jar包,然后修改build.gradle(Module),compileSdk、minSdk、targetSdk全部改成30,如下

android {
    compileSdk 30

    defaultConfig {
        applicationId "com.zzh.zzh.myapplication"
        minSdk 30
        targetSdk 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    ...
}    

在创建Client应用前,将这个Client应用设置为系统级应用,放置系统签名文件在Client项目的目录下,同时在build.gradle(Module)下增加如下:

android {
	...
	    signingConfigs {
        debug {
            storeFile file("../keystore/platform_ok.jks")
            storePassword = "xxxxxxxxxx"
            keyAlias = "platform"
            keyPassword = "xxxxxxxxxxx"
        }
    }
	...
}

如何生成keystore文件,可以自行百度,
同时对AndroidManifest.xml增加android:sharedUserId=“android.uid.system”,表示该应用一定要和系统平台签名一致要不然应用无法被解析安装:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zzh.zzh.myapplication"
    android:sharedUserId="android.uid.system">

最后,其java代码如下:

package com.zzh.kk.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;
import java.util.Vector;

import vendor.mediatek.hardware.touchserver.V1_0.IDataCallback;
import vendor.mediatek.hardware.touchserver.V1_0.ITestOfHidl;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "ApiImpl";
    private ITestOfHidl mTestOfHidl;
    private int channel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        try {
            mTestOfHidl = ITestOfHidl.getService();
            if (mTestOfHidl != null) {
                ArrayList<Byte> list = new ArrayList<Byte>();
                byte[] data = {0x01, 0x00, 0x00, 0x01, 0x00, 0x01};;
                for (byte datum : data) {
                    list.add(datum);
                }
                mTestOfHidl.sendData(list);
                channel= mTestOfHidl.setDataCallback(new IDataCallback.Stub() {
                    @Override
                    public void onDataReceived(ArrayList<Byte> data) throws RemoteException {
                        if ( data != null) {
                            byte[] result = new byte[data.size()];
                            Vector v1 = new Vector(data.size());
                            for (int i = 0; i < data.size(); i++) {
                                result[i] = data.get(i);
                                int k = result[i]&0xff;
                                v1.add(i,Integer.toHexString(k));
                                Log.d(TAG, "v1 = " +  v1.get(i));
                            }
                        }
                    }
                });
            }
        	mTestOfHidl.asBinder().linkToDeath(mDeathProxy, channel);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private IHwBinder.DeathRecipient mDeathProxy = new IHwBinder.DeathRecipient() {
        @Override
        public void serviceDied(long cookie) {
            Log.d(TAG, "mService serviceDied++ channel id = " + cookie);
            //延时3s,等待服务启动
            SystemClock.sleep(3000);
            //重连
            try {
                mTestOfHidl = ITestOfHidl.getService();
                if(mTestOfHidl != null){
                    channel = mTestOfHidl.setDataCallback(new IDataCallback.Stub(){...});
                    mTestOfHidl.asBinder().linkToDeath(mDeathProxy, channel);
                    Log.d(TAG,"channel = " + channel);
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            Log.d(TAG, "mService serviceDied--");
        }
    };
}

AS中TAG为ApiImpl的logcat可以看到如下:
在这里插入图片描述

总结:这个service的作用只有两个,上层app通过sendData发送数据到service,service对数据进行处理,在这里面,时对数据的第二位改写为1。


如有错误,请指正,谢谢

参考

https://blog.csdn.net/u013357557/article/details/84561652
https://blog.csdn.net/kehyuanyu/article/details/120904314?spm=1001.2014.3001.5502
https://www.codeleading.com/article/68254488842/#%E4%B8%89%E3%80%81SELinux%E9%83%A8%E5%88%86%E2%80%94%E2%80%94hal%20service
  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值