Android HAL HIDL

1 Android HAL HIDL
1.1 Android中查看有哪些HIDL HAL
HIDL是Treble Interface的一部分。
adb root
adb shell
# lshal

1.2 Android打印C++调用栈
#include <utils/CallStack.h> 
在需要打印的地方加如下的定义。
android::CallStack stack("oem");

logcat | grep oem

1.3 GNSS和Sensors
Refer to gnss and sensors
hardware/interfaces/gnss/1.0/default
hardware/interfaces/sensors/1.0/default

1.4 产生HAL框架步骤
1)生成androidmk和hidl-gen
在Android项目根目录下:

. build/envsetup.sh
lunch
make blueprint_tools
make hidl-gen
make c2hal // 将传统HAL .h头文件转换成hidl .hal文件工具

2)产生.cpp和.h文件
mkdir -p hardware/interfaces/oem1/1.0/default
路径中出现的1.0表示HAL当前版本

仿照GNSS或者Sensors增加一个IOem1.hal
in hardware/interfaces/oem1/1.0/IOem1.hal

在Android项目源码根目录下编写脚本my_oem1.sh,调用hidl-gen产生.cpp和.h文件
in my_oem1.sh
PACKAGE=android.hardware.oem1@1.0
LOC=hardware/interfaces/oem1/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

执行:
./my_oem1.sh

3)产生.bp和.mk文件
执行:
./hardware/interfaces/update-makefiles.sh

4)
编译最终在out/target/common/gen/JAVA_LIBRARIES目录下生成Java源文件。 

1.5 mk文件转换为bp文件
. build/envsetup.sh
make blueprint_tools
androidmk Android.mk > Android.bp

1.6 Java HIDL
[28th-Mar-2022]
./hardware/interfaces/update-makefiles.sh
Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += \
android.hardware.foo-V1.0-java
Android.bp
static_libs: [
"android.hardware.foo-V1.0-java",
],

// out/target/common/gen/JAVA_LIBRARIES
import android.hardware.foo.V1_0.IFoo;
IFoo server = IFoo.getService();

2 VTS测试步骤
1) 安装必须的python工具和adb - Linux需要
apt-get install android-tools-adb

2) 
source build/envsetup.sh
lunch
make vts

3) 编译完成后
in out/host/linux-x86/vts/
$cd android-vts/tools
$vts-tradefed
> run vts
or
> run vts-hal
or
> run vts-kernel

如果要在Windows上测试,需要将文件夹android-vts拷贝到windows下  - 待完善

4) 测试完成后
查看测试结果
android-vts/results
android-vts/logs

3 LinkToDeath
3.1 Principle
Client很容易监控Service的died;但是Service监控Client的died,需要Client实现使用IBinder接口的ICallback,传给Service,然后Service可以监控这个使用IBinder接口的ICallback的died,这样就实现了监控Client的died。

1)一个BpBinder可以注册多个死亡回调;但Kernel只允许注册一个死亡通知(ref->death只能为空或者指向一个指针)
2)BC_REQUEST_DEATH_NOTIFICATION - linkToDeath()
3)BC_CLEAR_DEATH_NOTIFICATION - unlinkToDeath()
4)当process exit时会触发系统关闭该进程已经打开的文件节点/dev/hwbinder,从而调用binder_node_release();通知died - BINDER_WORK_DEAD_BINDER
5)
echo 0x18 > /sys/module/binder/parameters/debug_mask
dmesg -C
dmesg -w | grep binder &
kill -9 $PID
6)ftrace as shown below
echo 0 > /d/tracing/tracing_on
echo nop > /d/tracing/current_tracer

echo function_graph > /d/tracing/current_tracer
#echo function > /d/tracing/current_tracer
echo funcgraph-proc > /d/tracing/trace_options

echo binder_cleanup_ref_olocked > /d/tracing/set_graph_function
echo 1 > /d/tracing/tracing_on

cat /d/tracing/trace

debuggerd -b $PID

3.2 JAVA实施步骤
import android.os.IHwBinder.DeathRecipient;

private class xxxDeathRecipient implements DeathRecipient {
    @Override
    public void serviceDied(long cookie) {
        Log.i(TAG, "serviceDied, re-connect XXX");
        if (xxxService != null) {
            xxxService.unlinkToDeath(this);
        }

        // TODO: 重连service
    }
};
xxxDeathRecipient mxxxDeathRecipient = new xxxDeathRecipient();

获取xxxService成功后:
try {
    xxxService.linkToDeath(mxxxDeathRecipient, 0);
} catch (RemoteException e) {
    e.printStackTrace();
}

3.3 CPP实施步骤
using android::hardware::hidl_death_recipient;

class MyDeathRecipient : public android::hardware::hidl_death_recipient {
    virtual void serviceDied(uint64_t cookie,
        const android::wp<::android::hidl::base::V1_0::IBase>& who) {
        // Deal with the fact that the service died
    }
}
MyDeathRecipient mDeathRecipient = new MyDeathRecipient();

获取xxxService成功后:
xxxService->linkToDeath(mDeathRecipient, 0);

4 strace解析binder驱动数据插件
4.1 知识
A进程给B进程发送数据:A进程使用BC_TRANSACTION发送,经过binder驱动转换,B进程接收到是BR_TRANSACTION
B进程给A进程回复数据:B进程使用BC_REPLY发送,经过binder驱动转换,A进程接收到是BR_REPLY。

4.2 代码
#include "defs.h"
#include <linux/android/binder.h>

static inline unsigned int get_my_le32(
    const unsigned char *p)
{
    return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
}

static const char *cmd_to_str(unsigned int cmd)
{
    switch(cmd) {
        case BC_TRANSACTION:
            return "BC_TRANSACTION";
            break;
        case BC_REPLY:
            return "BC_REPLY";
            break;
        case BR_TRANSACTION:
            return "BR_TRANSACTION";
            break;
        case BR_REPLY:
            return "BR_REPLY";
            break;
    }
    return "UNDEFINED";
}

/*
 * bc: binder command, from userland to driver
 * br: binder return, from driver to userland
 */
static void handle_bx_transaction(
        struct tcb *const tcp,
        struct binder_write_read *bwr,
        struct binder_transaction_data *txn)
{
    binder_size_t   txn_data_size = 0;
    binder_size_t   txn_offsets_size = 0;
#if defined (FEATURE_PRINT_DETAIL)
    int n = 0;
    unsigned char buf[256], buf_offsets[256];
#else
    binder_uintptr_t    txn_buffer;
    binder_uintptr_t    txn_offsets;
#endif

    txn_data_size = txn->data_size;
    txn_offsets_size = txn->offsets_size;
    tprintf("handle=%d, ptr=%llx, "
            "target_cookie=0x%llx,\n"
            "code=%d, flags=0x%02x, "
            "sender_pid=%d, sender_euid=%d",
            txn->target.handle,
            txn->target.ptr,
            txn->cookie,
            txn->code,
            txn->flags,
            txn->sender_pid,
            txn->sender_euid);
    if (txn_data_size <= 8) {
        tprintf(", data_size=%llu, "
               "%02x %02x %02x %02x "
                "%02x %02x %02x %02x\n",
                txn_data_size,
                txn->data.buf[0], txn->data.buf[1],
                txn->data.buf[2], txn->data.buf[3],
                txn->data.buf[4], txn->data.buf[5],
                txn->data.buf[6], txn->data.buf[7]);
    } else {
#if defined (FEATURE_PRINT_DETAIL)
        txn_data_size = (txn_data_size > 256) ?
                256 : txn_data_size;
        if (umoven(tcp,
                txn->data.ptr.buffer,
                txn_data_size, buf) < 0)
            return;
        txn_offsets_size = (txn_offsets_size > 256) ?
                256 : txn_offsets_size;
        if (umoven(tcp,
                txn->data.ptr.offsets,
                txn_offsets_size,
                buf_offsets) < 0)
            return;

        for (; n < (txn_offsets_size /
                sizeof(binder_size_t)); n++)
        {
            struct flat_binder_object* pbinder =
            (struct flat_binder_object*)((char*)buf +
                    ((int*)(buf_offsets))[n]);

            unsigned long type = pbinder->type;
            switch (type)
            {
                case BINDER_TYPE_BINDER:
                case BINDER_TYPE_WEAK_BINDER:
                    tprintf("binder=0x%llx, "
                            "cookie=0x%llx\n",
                            pbinder->binder,
                            pbinder->cookie);
                    break;

                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE:
                    tprintf("handle=0x%08x\n",
                            pbinder->handle);
                    break;
                default:
                    break;
            }
        }
#else
        txn_buffer = txn->data.ptr.buffer;
        txn_offsets = txn->data.ptr.offsets;
        tprintf(", \ndata_size=%llu, "
               "txn_buffer=0x%llx\n",
                txn_data_size, txn_buffer);
        dumpstr(tcp,
                (long) txn_buffer,
                txn_data_size);

        tprintf("\noffsets_size=%llu, "
                "txn_offsets=0x%llx\n",
                txn_offsets_size, txn_offsets);
        dumpstr(tcp,
               (long) txn_offsets,
               txn_offsets_size);
#endif
    }
}

/*
 * mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
 * GET_SERVICE_TRANSACTION <-> struct binder_transaction_data.code
 * data                    <-> struct binder_transaction_data.data
 *
 * write_bufer: CMD + binder_transaction_data + CMD + binder_transaction_data...
 * byte 0-3: command, offset0 - nr, offset1 - magic 'c' = 0x63
 * byte 4-7: target
 *
 * read_bufer: BR_NOOP + CMD + binder_transaction_data + CMD + binder_transaction_data...
 * byte 0-3:  BR_NOOP, 0c 72 00 00, offset0 - nr, offset1 - magic 'r' = 0x72
 *
 */
static void decode_bwr(struct tcb *const tcp,
        const kernel_ulong_t addr)
{
    struct binder_write_read bwr;
    struct binder_transaction_data *txn;
    int read_len, write_len, offset;
    unsigned char buf[256], *p;
    unsigned int cmd, cmd_data_len;
    static int ioctl_count = 1;

    if (umove_or_printaddr(tcp, addr, &bwr))
        return;
    if (abbrev(tcp)) {
        tprints(", ");
        tprintf("{BC_TRANS=0x%08x, "
                "BR_REPLY=0x%08x, "
                "write_size=%llu, "
                "write_consumed=%llu, "
                "read_size=%llu, "
                "read_consumed=%llu}",
                BC_TRANSACTION, BR_REPLY,
                bwr.write_size, bwr.write_consumed,
                bwr.read_size, bwr.read_consumed);
        return;
    }

    /* VERBOSE mode */
    tprints(",\n");
    tprintf("%d) ### WRITE ###\n",
            ioctl_count++);
    tprintf("write_size=%llu, "
            "write_consumed=%llu, "
             "write_buffer=\n",
            bwr.write_size,
            bwr.write_consumed);

    write_len = (bwr.write_size > 256) ?
            256 : bwr.write_size;
    if (umoven(tcp,
        bwr.write_buffer,
        write_len, buf) < 0)
        goto out;

    offset = 0;
    while (offset < write_len) {
        cmd = get_my_le32(buf + offset);
        cmd_data_len = _IOC_SIZE(cmd);

        switch (cmd) {
            case BC_TRANSACTION:
            case BC_REPLY:
                tprintf("%s--->\n", cmd_to_str(cmd));
                p = buf + offset + 4;
                txn = (struct binder_transaction_data *)p;
                handle_bx_transaction(tcp, &bwr, txn);
                break;
        }
        offset += (4 + cmd_data_len);
    }

    dumpstr(tcp,
        (long) bwr.write_buffer,
        bwr.write_size);
    tprints("\n");

    tprintf("%d) ### READ ###\n",
            ioctl_count++);
    tprintf("read_size=%llu, "
            "read_consumed=%llu,\n",
            bwr.read_size,
            bwr.read_consumed);
    read_len = (bwr.read_size > 256) ?
                        256 : bwr.read_size;
    if (umoven(tcp,
        bwr.read_buffer,
        read_len, buf) < 0)
        goto out;

    offset = 0;
    while (offset < read_len) {
        cmd = get_my_le32(buf + offset);
        cmd_data_len = _IOC_SIZE(cmd);

        switch (cmd) {
            case BR_TRANSACTION:
            case BR_REPLY:
                tprintf("%s--->\n", cmd_to_str(cmd));
                p = buf + offset + 4;
                txn = (struct binder_transaction_data *)p;
                handle_bx_transaction(tcp, &bwr, txn);
                break;
        }
        offset += (4 + cmd_data_len);
    }

    tprints("\n");
    dumpstr(tcp,
        (long) bwr.read_buffer,
        bwr.read_size);
out:
    tprints("}");
}

int binder_ioctl(struct tcb *const tcp,
    const unsigned int code,
    const kernel_ulong_t arg)
{
    switch (code) {
        case BINDER_WRITE_READ:
            decode_bwr(tcp, arg);
            break;

        default:
            return RVAL_DECODED;
    }
    return RVAL_DECODED | 1;
}

4.3 查看hwbinder的数据
ps -A| grep hwservicemanager
strace -tt -T -x -v -p $PID 2>&1 |grep -vE "writev|futex|getuid|ppoll"

5 Abbreviations
VTS:Vendor Test Suite

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/77356.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AI 加持下的 Python 编程实战 2_11】DIY 拓展:从扫雷小游戏开发再探问题分解与 AI 代码调试能力(下)

&#xff08;接 上篇&#xff09; 5 复盘与 Copilot 的交互过程 前面两篇文章分别涵盖了扫雷游戏的问题分解和代码实现过程&#xff0c;不知道各位是否会有代码一气呵成的错觉&#xff1f;实际上&#xff0c;为了达到最终效果&#xff08;如下所示&#xff09;&#xff0c;我…

游戏状态管理:用Pygame实现场景切换与暂停功能

游戏状态管理:用Pygame实现场景切换与暂停功能 在开发游戏时,管理游戏的不同状态(如主菜单、游戏进行中、暂停等)是非常重要的。这不仅有助于提升玩家的游戏体验,还能使代码结构更加清晰。本文将通过一个简单的示例,展示如何使用Pygame库来实现游戏中的场景切换和暂停功…

Java后端开发day36--源码解析:HashMap

&#xff08;以下内容均来自上述课程&#xff09; 1. HashMap&#xff08;一&#xff09; 底层&#xff1a;数组链表红黑树 1.1 前提准备 查看源码&#xff1a;选中HashMap–ctrlB 小细节&#xff1a;快捷键ctrlf12–跳出目录结构 蓝色圆圈&#xff1a;class 证明是类名粉…

RT-Thread学习笔记(四)

RT-Thread学习笔记 线程间同步信号量信号量的使用和管理动态创建信号量静态创建信号量获取信号量信号量同步实列互斥量互斥量的使用和管理互斥量动态创建互斥量静态创建互斥量获取和释放互斥量实例事件集事件集的使用和管理动态创建事件集静态初始化事件集发送和接收事件事件集…

element ui el-col的高度不一致导致换行

问题&#xff1a;ell-col的高度不一致导致换行&#xff0c;刷新后审查el-col的高度一致 我这边是el-col写的span超过了24&#xff0c;自行换行&#xff0c;测试发现初次进入里面的高度渲染的不一致&#xff0c;有的是51px有的是51.5px 问题原因分析 Flex布局换行机制 Elemen…

现代化Android开发:Compose提示信息的最佳封装方案

在 Android 开发中&#xff0c;良好的用户反馈机制至关重要。Jetpack Compose 提供了现代化的 UI 构建方式&#xff0c;但提示信息(Toast/Snackbar)的管理往往显得分散。本文将介绍如何优雅地封装提示信息&#xff0c;提升代码可维护性。 一、基础封装方案 1. 简单 Snackbar …

【C++语法】类和对象(2)

4.类和对象&#xff08;2&#xff09; 文章目录 4.类和对象&#xff08;2&#xff09;类的六个默认成员函数(1)构造函数&#xff1a;构造函数特点含有缺省参数的构造函数构造函数特点&#xff08;续&#xff09;注意事项构造函数补充 前面总结了有关对象概念&#xff0c;对比 C…

【自然语言处理与大模型】vLLM部署本地大模型②

举例上一篇文章已经过去了几个月&#xff0c;大模型领域风云变幻&#xff0c;之前的vLLM安装稍有过时&#xff0c;这里补充一个快速安装教程&#xff1a; # 第一步&#xff1a;创建虚拟环境并激活进入 conda create -n vllm-0.8.4 python3.10 -y conda activate vllm-0…

26 Arcgis软件常用工具有哪些

一、画图改图工具&#xff08;矢量编辑&#xff09;‌ ‌挪位置工具&#xff08;移动工具&#xff09;‌ 干哈的&#xff1f;‌选中要素‌&#xff08;比如地块、道路&#xff09;直接拖到新位置&#xff0c;或者用坐标‌X/Y偏移‌批量移动&#xff0c;适合“整体搬家”。 ‌磁…

QNX/LINUX/Android系统动态配置动态库.so文件日志打印级别的方法

背景 通常我们会在量产的产品上&#xff0c;配置软件仅打印少量日志&#xff0c;以提升产品的运行性能。同时我们要考虑预留方法让软件能够拥有能力可以在烧录版本后能够通过修改默写配置&#xff0c;打印更多日志。因为量产后的软件通常开启熔断与加密&#xff0c;不能够轻松…

WebGL图形编程实战【4】:光影交织 × 逐片元光照与渲染技巧

现实世界中的物体被光线照射时&#xff0c;会反射一部分光。只有当反射光线进人你的眼睛时&#xff0c;你才能够看到物体并辩认出它的颜色。 光源类型 平行光&#xff08;Directional Light&#xff09;&#xff1a;光线是相互平行的&#xff0c;平行光具有方向。平行光可以看…

【Hive入门】Hive基础操作与SQL语法:DDL操作全面指南

目录 1 Hive DDL操作概述 2 数据库操作全流程 2.1 创建数据库 2.2 查看数据库 2.3 使用数据库 2.4 修改数据库 2.5 删除数据库 3 表操作全流程 3.1 创建表 3.2 查看表信息 3.3 修改表 3.4 删除表 4 分区与分桶操作 4.1 分区操作流程 4.2 分桶操作 5 最佳实践与…

YOLO数据处理

YOLO&#xff08;You Only Look Once&#xff09;的数据处理流程是为了解决目标检测领域的核心挑战&#xff0c;核心目标是为模型训练和推理提供高效、规范化的数据输入。其设计方法系统性地解决了以下关键问题&#xff0c;并对应发展了成熟的技术方案&#xff1a; 一、解决的问…

Ubuntu-Linux中vi / vim编辑文件,保存并退出

1.打开文件 vi / vim 文件名&#xff08;例&#xff1a; vim word.txt &#xff09;。 若权限不够&#xff0c;则在前方添加 sudo &#xff08;例&#xff1a;sudo vim word.txt &#xff09;来增加权限&#xff1b; 2.进入文件&#xff0c;按 i 键进入编辑模式。 3.编辑结…

PCL绘制点云+法线

读取的点云ASCII码文件&#xff0c;每行6个数据&#xff0c;3维坐标3维法向 #include <iostream> #include <fstream> #include <vector> #include <string> #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pc…

如何在学习通快速输入答案(网页版),其他学习平台通用,手机上快速粘贴

目录 1、网页版&#xff08;全平台通用&#xff09; 2、手机版&#xff08;学习通&#xff0c;其他平台有可能使用&#xff09; 1、网页版&#xff08;全平台通用&#xff09; 1、首先CtrlC复制好答案 2、在学习通的作业里输入1 3、对准1&#xff0c;然后鼠标右键 &#xff…

002 六自由度舵机机械臂——姿态解算理论

00 DH模型的核心概念 【全程干货【六轴机械臂正逆解计算及仿真示例】】 如何实现机械臂的逆解计算-机器谱-robotway DH模型是机器人运动学建模的基础方法&#xff0c;通过​​四个参数​​描述相邻关节坐标系之间的变换关系。其核心思想是将复杂的空间位姿转换分解为绕轴旋转…

pymongo功能整理与基础操作类

以下是 Python 与 PyMongo 的完整功能整理&#xff0c;涵盖基础操作、高级功能、性能优化及常见应用场景&#xff1a; 1. 安装与连接 (1) 安装 PyMongo pip install pymongo(2) 连接 MongoDB from pymongo import MongoClient# 基础连接&#xff08;默认本地&#xff0c;端口…

Trae+DeepSeek学习Python开发MVC框架程序笔记(四):使用sqlite存储查询并验证用户名和密码

继续通过Trae向DeepSeek发问并修改程序&#xff0c;实现程序运行时生成数据库&#xff0c;用户在系统登录页面输入用户名和密码后&#xff0c;控制器通过模型查询用户数据库表来验证用户名和密码&#xff0c;验证通过后显示登录成功页面&#xff0c;验证失败则显示登录失败页面…

如何识别金融欺诈行为并进行分析预警

金融行业以其高效便捷的服务深刻改变了人们的生活方式。然而,伴随技术进步而来的,是金融欺诈行为的日益猖獗。从信用卡盗刷到复杂的庞氏骗局,再到网络钓鱼和洗钱活动,金融欺诈的形式层出不穷,其规模和影响也在不断扩大。根据全球反欺诈组织(ACFE)的最新报告,仅2022年,…