本文基于android13,实现aidl hal服务,以及app如何使用这个aidl和hal交互。
最终实现得hal demo目录层级结构如下:

uluxy181@NJUbuntu18-210:~/workspace1/UIS7870_SAIC/android/vendor/yfe/saic_project/common/hardware/interfaces/demo$ tree
.
└── 1.0
    ├── aidl
    │   └── vendor
    │       └── yfe
    │           └── hardware
    │               └── demo
    │                   └── IDemo.aidl
    ├── aidl_api
    │   └── vendor.yfe.hardware.demo
    │       ├── 1
    │       │   └── vendor
    │       │       └── yfe
    │       │           └── hardware
    │       │               └── demo
    │       │                   └── IDemo.aidl
    │       └── current
    │           └── vendor
    │               └── yfe
    │                   └── hardware
    │                       └── demo
    │                           └── IDemo.aidl
    ├── Android.bp
    └── default
        ├── Android.bp
        ├── DemoService.cpp
        ├── DemoService.h
        ├── service.cpp
        ├── vendor.yfe.hardware.demo-service.rc
        └── vendor.yfe.hardware.demo-service.xml

19 directories, 10 files

接下来我们一步步实现。

1,实现aidl接口

1.1 实现文件IDemo.aidl:

package vendor.yfe.hardware.demo;

@VintfStability 
interface IDemo {
    // 简单测试接口:获取字符串
    String getHelloString();
    // 加法计算
    int add(int a, int b);
    // 设置/获取值
    void setValue(int val);
    int getValue();
}

1.2 实现对应得Android.bp文件

我们是实现需要固定接口得量产版aidl接口

package {
    //    default_visibility: ["//..."],
}

aidl_interface {
    name: "vendor.yfe.hardware.demo",
    vendor_available: true,
    srcs: ["aidl/vendor/yfe/hardware/demo/IDemo.aidl"],
    //unstable: true,
    owner: "yfe",
    stability: "vintf",
    visibility: [
        "//system/tools/aidl/build",
        "//vendor/...",
    ],
    backend: {
        cpp: {
            enabled: true,
        },
        java: {
            enabled: true,//生成java接口
        },
        ndk: {
            enabled: true, // 关键:生成供 NDK 使用的库
        },
    },
    versions_with_info: [
        {
            version: "1",
            imports: [],
        },
    ],

}

1.3 编译,生成aidl接口

m指令或者make指令编译aidl。

android$ m vendor.yfe.hardware.demo

编译可能会遇到报错

error: vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/Android.bp:8:9: module "vendor.yfe.hardware.demo_interface": srcs: No sources for a previous version in aidl_api/vendor.yfe.hardware.demo/1. Was a version manually added to .bp file? This is added automatically by <module>-freeze-api.
error: vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/Android.bp:8:9: module "vendor.yfe.hardware.demo_interface": srcs: No sources provided in aidl_api/vendor.yfe.hardware.demo/1
21:42:26 soong bootstrap failed with: exit status 1

根据报错提醒,执行m vendor.demo.hal-freeze-api ,或者执行m vendor.yfe.hardware.demo-update-api,但是还是会报错,本人放弃了这种方式,采用手动创建aidl_api/vendor.yfe.hardware.demo/1/vendor/yfe/hardware/demo/IDemo.aidl
继续编译,又报新错

error: vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/Android.bp:5:1: module "vendor.yfe.hardware.demo-api" (created by module "vendor.yfe.hardware.demo_interface"): A frozen aidl_interface must have '.hash' file, but vendor.yfe.hardware.demo-V1 doesn't have it. Use the command below to generate hash.
(croot && system/tools/aidl/build/hash_gen.sh vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1 latest-version vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1/.hash)

按照报错指令执行

croot && system/tools/aidl/build/hash_gen.sh vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1 latest-version vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1/.hash

然后执行m vendor.demo.hal-freeze-api生成aidl_api/vendor.yfe.hardware.demo/current/vendor/yfe/hardware/demo/IDemo.aidl

android$ m vendor.demo.hal-freeze-api

至此aidl接口编译完成:

└── 1.0
    ├── aidl
    │   └── vendor
    │       └── yfe
    │           └── hardware
    │               └── demo
    │                   └── IDemo.aidl
    ├── aidl_api
    │   └── vendor.yfe.hardware.demo
    │       ├── 1
    │       │   └── vendor
    │       │       └── yfe
    │       │           └── hardware
    │       │               └── demo
    │       │                   └── IDemo.aidl
    │       └── current
    │           └── vendor
    │               └── yfe
    │                   └── hardware
    │                       └── demo
    │                           └── IDemo.aidl
    ├── Android.bp

2,实现HAL服务功能

实现default目录下创建源文件、rc、xml、bp

 default
        ├── Android.bp
        ├── DemoService.cpp
        ├── DemoService.h
        ├── service.cpp
        ├── vendor.yfe.hardware.demo-service.rc
        └── vendor.yfe.hardware.demo-service.xml

DemoService.h:

#ifndef VENDOR_YFE_HARDWARW_DEMO_SERVICE_H
#define VENDOR_YFE_HARDWARW_DEMO_SERVICE_H

#include <aidl/vendor/yfe/hardware/demo/IDemo.h>
#include <aidl/vendor/yfe/hardware/demo/BnDemo.h>

namespace aidl::vendor::yfe::hardware::demo {

class DemoService : public BnDemo {
public:
    DemoService();

    ndk::ScopedAStatus getHelloString(std::string* _aidl_return) override;
    ndk::ScopedAStatus add(int32_t a, int32_t b, int32_t* _aidl_return) override;
    ndk::ScopedAStatus setValue(int32_t val) override;
    ndk::ScopedAStatus getValue(int32_t* _aidl_return) override;

private:
    int32_t mValue = 0;
};

}

#endif

DemoService.cpp:

#include "DemoService.h"

namespace aidl::vendor::yfe::hardware::demo {

DemoService::DemoService() = default;

ndk::ScopedAStatus DemoService::getHelloString(std::string* _aidl_return) {
    *_aidl_return = "Hello from Vendor Demo HAL!";
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus DemoService::add(int32_t a, int32_t b, int32_t* _aidl_return) {
    *_aidl_return = a + b;
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus DemoService::setValue(int32_t val) {
    mValue = val;
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus DemoService::getValue(int32_t* _aidl_return) {
    *_aidl_return = mValue;
    return ndk::ScopedAStatus::ok();
}

}

Hal服务入口service.cpp:

#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "DemoService.h"
#include <utils/Log.h>

using namespace aidl::vendor::yfe::hardware::demo;

int main() {
    ABinderProcess_setThreadPoolMaxThreadCount(4);
    ABinderProcess_startThreadPool();

    std::shared_ptr<IDemo> service = ndk::SharedRefBase::make<DemoService>();
    const std::string name = IDemo::descriptor + std::string("/default");//get service name

    if (AServiceManager_addService(service->asBinder().get(), name.c_str()) == STATUS_OK) {
        ALOGI("vendor demo hal service registered: %s", name.c_str());
    } else {
        ALOGE("failed to add service");
        return -1;
    }

    ABinderProcess_joinThreadPool();
    return 0;
}

vendor.yfe.hardware.demo-service.rc:

service vendor.yfe.hardware.demo /vendor/bin/hw/vendor.yfe.hardware.demo-service
    class hal
    user root
    group root
    oneshot

vendor.yfe.hardware.demo-service.xml:

<manifest version="1.0" type="device">
    <hal format="aidl">
        <name>vendor.yfe.hardware.demo</name>
        <version>1</version>
        <interface>
            <name>IDemo</name>
            <instance>default</instance>
        </interface>
    </hal>
</manifest>

Android.bp:

cc_binary {
    name: "vendor.yfe.hardware.demo-service",
    soc_specific:true,
    init_rc: ["vendor.yfe.hardware.demo-service.rc"],
    relative_install_path: "hw",
    vintf_fragments: ["vendor.yfe.hardware.demo-service.xml"],

    srcs: [
        "service.cpp",
        "DemoService.cpp",
    ],

    shared_libs: [
        "libbinder_ndk",
        "libcutils",
        "libutils",
	"liblog",
        //"vendor.demo.hal-ndk",
	"vendor.yfe.hardware.demo-V1-ndk",
    ],

    cflags: [
        "-Wall",
        "-Werror",
    ],
}

编译:

$ m vendor.yfe.hardware.demo-service

遇到了报错:

[ 92% 207/224] echo "API dump for the current version of AIDL interface vendor.yfe.hardware.demo does not exist." && echo Run "m vendor.yfe.hardware.demo-update-api", or add "unstable: true" to the build 
FAILED: out/soong/.intermediates/vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/vendor.yfe.hardware.demo-api/checkapi_current.timestamp
echo "API dump for the current version of AIDL interface vendor.yfe.hardware.demo does not exist." && echo Run "m vendor.yfe.hardware.demo-update-api", or add "unstable: true" to the build rule for the interface if it does not need to be versioned && false # hash of input list: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
API dump for the current version of AIDL interface vendor.yfe.hardware.demo does not exist.
Run m vendor.yfe.hardware.demo-update-api, or add unstable: true to the build rule for the interface if it does not need to be versioned

可以重新生成一下.hash
手动删除

android/vendor/yfe/saic_project/common/hardware/interfaces/demo1/vendor/yfe/hardware/demo$ rm -rf .hash
android/vendor/yfe/saic_project/common/hardware/interfaces/demo1/vendor/yfe/hardware/demo$ croot
android$ system/tools/aidl/build/hash_gen.sh vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1 latest-version vendor/yfe/saic_project/common/hardware/interfaces/demo/1.0/aidl_api/vendor.yfe.hardware.demo/1/.hash

如果出现类似下面报错信息

The following HALs in device manifest are not declared in FCM <= level 7: 
  vendor.yfe.hardware.demo.IDemo/default (@1)
ERROR: files are incompatible: The following instances are in the device manifest but not specified in framework compatibility matrix: 
    vendor.yfe.hardware.demo.IDemo/default (@1)
Suggested fix:
1. Update deprecated HALs to the latest version.
2. Check for any typos in device manifest or framework compatibility matrices with FCM version >= 7.
3. For new platform HALs, add them to any framework compatibility matrix with FCM version >= 7 where applicable.
4. For device-specific HALs, add to DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE or DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE.: Success
INCOMPATIBLE
20:07:09 ninja failed with: exit status 1

原因是我得基线原生得product/soc/msoc/qogirn6pro/march/arm64/manifest.xml里写死了
所以我得vendor.yfe.hardware.demo-service.xml里不能带target-level版本号

3,添加manifest.xml

在项目目录android/vendor/yfe/saic_project/common/device/manifest下创建manifest.mk、vendor_framework_compatibility_matrix.xml

android/vendor/yfe/saic_project/common/device/manifest$ cat manifest.mk
DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE += \
    vendor/yfe/saic_project/common/device/manifest/vendor_framework_compatibility_matrix.xml


android/vendor/yfe/saic_project/common/device/manifest$ cat vendor_framework_compatibility_matrix.xml
<compatibility-matrix version="1.0" type="framework">
    <hal format="aidl" optional="true">
        <name>vendor.yfe.hardware.demo</name>
        <version>1</version>
        <interface>
            <name>IDemo</name>
            <instance>default</instance>
        </interface>
    </hal>
</compatibility-matrix>

然后在项目主mk文件saic_car.mk里include 这个manifest.mk,同时将加入打包vendor.yfe.hardware.demo-service

android/vendor/yfe/saic_project/common/device$ cat saic_car.mk
... ...
-include vendor/yfe/saic_project/common/device/manifest/manifest.mk
PRODUCT_PACKAGES += \
    vendor.yfe.hardware.demo-service \
    vendor.yfe.hardware.demo-V1-java //这个需要加,不然不生成jar包

至此再整编系统试一下,应该就可以编过了

4,添加selinux相关

vendor/yfe/saic_project/common/device/sepolicy/vendor/目录下创建demo_service.te,file_contexts,hwservice_contexts。如果项目已有file_contexts,hwservice_contexts,则只用添加声明即可。
声明hwservice_contexts:

vendor/yfe/saic_project/common/device/sepolicy$ cat vendor/hwservice_contexts
#add for demo
vendor.yfe.hardware.demo::IDemo/default	u:object_r:demo_hwservice_t:s0

声明file_contexts:

... ...
/vendor/bin/hw/vendor.yfe.hardware.demo-service                        u:object_r:demo_service_t_exec:s0

demo_service.te:

android/vendor/yfe/saic_project/common/device/sepolicy$ cat vendor/demo_service.te
# 基础类型定义(车载Android13 100%兼容)
type demo_service_t, domain;
type demo_service_t_exec, exec_type, file_type, vendor_file_type;
type demo_hwservice_t, hwservice_manager_type;

# 允许init启动服务
init_daemon_domain(demo_service_t)

# Binder基础权限(必须)
binder_use(demo_service_t)
binder_service(demo_service_t)
add_hwservice(demo_service_t, demo_hwservice_t)

# 允许APP访问
# allow platform_app_t demo_hwservice_t:hwservice_manager find;
# allow system_app_t demo_hwservice_t:hwservice_manager find;
# allow untrusted_app_t demo_hwservice_t:hwservice_manager find;

# allow platform_app_t demo_service_t:binder call;
# allow system_app_t demo_service_t:binder call;
# allow untrusted_app_t demo_service_t:binder call;

经过aidl接口声明,HAL服务实现,manifest.xml aidl接口声明,selinux处理等流程后,aidl hal服务基本完成。整编系统,烧录机器。查看服务是否开机启动

5,APP验证接口是否可用

jar包生成物在out目录位置out/target/common/obj/JAVA_LIBRARIES/vendor.yfe.hardware.demo-V1-java_intermediates/classes.jar

5.1,jar引用

Android Studio工程下创建libs目录
取出jar包放在工程源码libs目录
build.gradle文件里添加implementation files(‘libs/classes.jar’)

... ....
dependencies {
    //compileOnly files('libs/classes.jar')
    implementation files('libs/classes.jar')//添加
    implementation libs.appcompat
    implementation libs.material
    implementation libs.activity
    implementation libs.constraintlayout
    testImplementation libs.junit
    androidTestImplementation libs.ext.junit
    androidTestImplementation libs.espresso.core
}
... ...

5.2,Aidl接口使用

见下面:

package com.example.aidlhal;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import vendor.yfe.hardware.demo.IDemo;//引用头文件

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button bt_1;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        bt_1 = findViewById(R.id.bt_1);
        bt_1.setOnClickListener(this);
        Log.d("luyao7870","000000000000");
        getService();
        try {
            Log.d("luyao7870","bt_1 0000000000");
            getService().add(1,2);//调用Aidl接口验证功能是否正常
        } catch (RemoteException e) {
            Log.d("luyao7870","bt_1 111111111111");
            throw new RuntimeException(e);
        }
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
            if(id == R.id.bt_1) {
                Log.d("luyao7870","bt_1");
                try {
                    Log.d("luyao7870","bt_1 0000000000");
                    getService().add(1,2);//调用Aidl接口验证功能是否正常
                } catch (RemoteException e) {
                    Log.d("luyao7870","bt_1 111111111111");
                    throw new RuntimeException(e);
                }


            } else {
                Log.d("luyao7870","else");
            }


        }

//获取AIDL服务对象
    public static IDemo getService() {
        try {
            // 反射获取 ServiceManager
            Class<?> smClass = Class.forName("android.os.ServiceManager");
            java.lang.reflect.Method getService = smClass.getMethod("getService", String.class);
            IBinder binder = (IBinder) getService.invoke(null, "vendor.yfe.hardware.demo.IDemo/default");//根据服务名得到binder对象

            if (binder == null) {
                Log.d("luyao7870","getService null");
                return null;
            }
            Log.d("luyao7870","getService ! null");
            return IDemo.Stub.asInterface(binder);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐