提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
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