Android NDK开发之震动服务客户端编写程序(C++)

一、背景

最近有个小伙伴问我可不可以写一个可执行程序(C/C++) 来实现Android设备的震动的功能。 作为一个多年的Android开发者,我觉得这是可以实现的。 但是由于过去我一直做App开发,也就把这个实现过程想简单了。 经过了几天的折腾,终于算是实现了这个程序。 本文就是记录一下 整个“折腾”的经历。

环境描述: Android12 (由于AOSP针对于 "震动服务"的架构 在Android12上有调整)
开发工具: Android Studio
开发形式: NDK

二、实现思路

  • 思路一: 获取到VibratorManagerService对相应的BpBinder对象,然后进行IPC通信。
  • 思路二: 模拟VibratorManagerService,直接“访问硬件”,实震动效果。
  • 思路三: 写在最后(苦笑~~)。

当我被问到这个问题的时候,我首先想到了前面两种实现方式,但是又考虑到 “思路二” 直接“访问硬件设备” 不太符合Android的架构理念, 故想尝试一下“方式一”的实现。

2.1 可行性分析

熟悉binder架构的同学,可能都知道:android系统中的binder ipc 就是通过native层调用驱动层来实现的。即便在应用层开发的时候,我们常采用的AIDL,其本质上也是通过native的bpbinder和bbinder实现。 具体的原理,可以看一下面的这张图:

在这里插入图片描述

同上图中看出 Bpbinder 与 Bbinder 是成对儿且对等的;同理在上层Binder.Stub 与 BinderProxy是成对儿且对等的。

我们是可以实现通过native层的bpbinder调用到java层的BinderServer对象(例如:IPackageManger.Stub)。

2.2 VibratorManagerService 结构图

在这里插入图片描述

从上图中VibratorManagerService(后面简称‘VMS’)的结构中,我们可以看出:

要想实现编写一个C++可执行程序实现控制振动器的功能,需要两个:a. 获取VibratorManagerService的代理对象 b. 遵顼IVbratorManagerService AIDL协议

三、功能实现 VibratorManagerService 结构图

  • 获取VMS代理对象
    • 获取SM代理对象
    • 获取VMS代理对象
  • AIDL协议生成
  • 编译构建
  • 测试IPC调用

3.1 获取VMS代理对象

熟悉AOSP源码的小伙伴,可能都会知道:获取一个BinderProxy代理对象,是通过ServiceManager的代理对象来完成的。 因此咱们要做的第一步就是拿到SM代理对象,然后再通过SM代理对象去“getService”拿到VMS代理对象。

3.1.1 导入libbinder.so并获取SM代理对象

AOSP中,Native层获取SM代理对象的方式是:

sp<IServiceManager> sm = defaultServiceManager();

defaultServiceManager() 函数是定义在IServiceManager.h中,但是在NDK中,binder包下并没有IServiceManager.h
因此我们只能将 libbinder.so 以第三方库的形式导入到项目中,并将相关的 头文件拷贝进来。

3.1.1.1 导入 libbinder.so

AOSP中,构建libinder.so 时, 依赖了 liblog.so , libcutils.so , libutils.so ,因此需要依次导入:

// frameworks/native/libs/binder/Android.bp
cc_library_shared {
    name: "libbinder",
    ...
    ...
    shared_libs: [
        "libbase",
        "liblog",
        "libcutils",
        "libutils",
        "libbinderthreadstate",
    ]
    ...
}

在这里插入图片描述

接下来就是每个头文件的导入:

这里笔者是根据so对应的android.bp文件,找到对应“导出头文件”

在这里插入图片描述

头文件目录如下

库名称头文件路径备注
libbinder.soframeworks/native/include/binder/*
frameworks/native/include/binder/*
libutils.sosystem/core/libutils/include/utils/*
liblog.sosystem/logging/liblog/include/log/*
其它system/core/libsystem/include/system/*

详情可以见下面的demo

3.1.1.2 获取SM代理对象
sp<IServiceManager> sm = defaultServiceManager();

3.1.2 获取VMS代理对象

sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("vibrator_manager"));
if (binder != nullptr) {
    LOGD("Sharknade Binder info: %p", binder.get());
}

编译成功之后, 测试结果如下:
在这里插入图片描述

获得VMS代理成功了 ,接下是就是如何使用该代理对象进行RPC通信了。

3.2 AIDL协议生成

Android SDK中 提供了AIDL工具,可以实现AIDL文件转C++、Java、NDK等形式转换。 我们可以通过该工具 快速获得VMS 相关的头文件。
VMS相关的AIDL文件有5个:

  • IVibratorManagerService.aidl
  • CombinedVibration.aidl
  • IVibratorStateListener.aidl
  • VibrationAttributes.aidl
  • VibratorInfo.aidl

执行下面的shell,获得对应的头文件:

<SDK_PATH>/build-tools/31.0.0/aidl -h ./ -o ./ --lang=cpp -I ./aidl  aidl/android/os/IVibratorManagerService.aidl
<SDK_PATH>/build-tools/31.0.0/aidl -h ./ -o ./ --lang=cpp -I ./aidl  aidl/android/os/CombinedVibration.aidl
<SDK_PATH>/build-tools/31.0.0/aidl -h ./ -o ./ --lang=cpp -I ./aidl  aidl/android/os/IVibratorStateListener.aidl
<SDK_PATH>/build-tools/31.0.0/aidl -h ./ -o ./ --lang=cpp -I ./aidl  aidl/android/os/VibrationAttributes.aidl
<SDK_PATH>/build-tools/31.0.0/aidl -h ./ -o ./ --lang=cpp -I ./aidl  aidl/android/os/VibratorInfo.aidl
参数含义
-h生成的头文件路径
-o生成的源文件路径
-I导入的头文件路径

3.3 编译构建项目

3.3.1 项目整体结构

在这里插入图片描述

目录功能
aidlVMS(VibratorManagerService) 相关的AIDL文件
so项目依赖的so目录
include项目依赖的so对应的导出头文件
vibrator_main.cpp主程序入口
CmakeLists.txtCmake构建脚本
*.hAIDL生成的头文件

*.h 头文件的间的关系:

在这里插入图片描述

3.3.2 CmakeLists内容及注意事项

cmake_minimum_required(VERSION 3.22.1)

project("vibrator_sample")

# 设置C++标准为C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# -fno-rtti 这个标记很重要,否则编译不通过。
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")

set(VIBRATOR vibrator_main)
include_directories(include)
add_executable(${VIBRATOR}
        vibrator_main.cpp
        IVibratorManagerService.h
        BpVibratorManagerService.h
        CombinedVibration.h
        IVibratorStateListener.h
        VibrationAttributes.h
        VibratorInfo.h
        IVibratorManagerService.cpp
        )

set_target_properties(${VIBRATOR} PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/out
        )

# 指定NDK的STL库
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -stdlib=libc++")

set(SHARED_LIB_DIR ${CMAKE_SOURCE_DIR}/so)
link_directories(${SHARED_LIB_DIR})

add_library(binder SHARED IMPORTED)
set_target_properties(binder PROPERTIES IMPORTED_LOCATION ${SHARED_LIB_DIR}/libbinder.so)

add_library(cutils SHARED IMPORTED)
set_target_properties(cutils PROPERTIES IMPORTED_LOCATION ${SHARED_LIB_DIR}/libcutils.so)

add_library(utils SHARED IMPORTED)
set_target_properties(utils PROPERTIES IMPORTED_LOCATION ${SHARED_LIB_DIR}/libutils.so)

add_library(log SHARED IMPORTED)
set_target_properties(log PROPERTIES IMPORTED_LOCATION ${SHARED_LIB_DIR}/liblog.so)


# 链接目标库
target_link_libraries(
        ${VIBRATOR}
        binder
        utils
        cutils
        log
)

3.4 测试结果

右侧执行 vibrator_main 可执行程序,左侧通过adb 能够看到RPC调用日志。
在这里插入图片描述

四、实现思路三(补充)

该功能可以通过shell实现

我在查看VibratorManagerService源码时,发现该执行shell命令操作:

class VibratorManagerService {
    @Override
    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
          String[] args, ShellCallback cb, ResultReceiver resultReceiver) {
        new VibratorManagerShellCommand(this).exec(this, in, out, err, args, cb, resultReceiver);
    }
    
    private final class VibratorManagerShellCommand extends ShellCommand {
        public static final String SHELL_PACKAGE_NAME = "com.android.shell";
        ...
        ...
    }
}

因此,用下面的命令,也可以实现震动效果。

adb shell
cmd vibrator_manager synced oneshot 100 #执行震动操作

那么,我们可以写一个执行shell的C++程序来完成此功能。

五、写在最后

Demo功能地址

ADB 相关命令



最后,欢迎小伙伴关注我的公众号(主要内容Android、鸿蒙、FW、C/C++等),一起成长进步。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【python学习】numpy第三方库的定义、功能、使用场景和使用以及遇到的一些问题

引言 python学习学习到第三方库知识&#xff0c;首先学习的就是机器学习以及对应的numpy第三方库 文章目录 引言一、numpy第三方库的定义二、numpy第三方库的功能2.1数组操作2.2 线性代数计算2.3 随机数生成2.4 文件读写 三、numpy第三方库的使用场景3.1需要进行数值计算3.2 需…

【连续四届EI检索|稳定ACM出版、EI检索|线上线下结合】2024年第五届医学人工智能国际学术会议(ISAIMS 2024,8月13-17)

第五届医学人工智能国际学术会议&#xff08;ISAIMS2024&#xff09;将于2024年8月13-17日于荷兰阿姆斯特丹自由大学召开&#xff0c;国内分会场将于2024年10月25-27日于中国武汉召开。 会议自2020年至今已经成功举办四届&#xff0c;吸引了来自海内外相关领域学者600余名。本届…

C# Opencv实现本地以图搜图

地址&#xff1a;冯腾飞/本地以图搜图

【找不到视图问题解决】@RestController 与 @Controller注解的使用区别

一、问题描述 苍穹外卖在菜品分页查询功能实现的过程中&#xff0c;出现了找不到视图的情况 2024-07-12 21:54:20.860 ERROR 22488 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with p…

OpenSceneGraph学习笔记

目录 引言第一章&#xff1a;OSG概述一、前言&#xff08;1&#xff09;为什么要学习OSG?&#xff08;2&#xff09;OSG的组成&#xff08;3&#xff09;OSG的智能指针&#xff08;4&#xff09;OSG的安装编译 二、第一个OSG程序&#xff08;1&#xff09;Hello OSG程序&#…

移动UI:具备什么特征,可以被认定为科技风格。

移动UI设计在科技风格上通常具备以下特征&#xff1a; 1. 清晰简洁的排版&#xff1a; 科技风格的移动UI通常采用清晰简洁的排版&#xff0c;注重信息的层次感和结构化&#xff0c;以便用户能够快速、直观地获取所需信息。 2. 几何形状和线条&#xff1a; 科技风格的移动UI常…

Vscode ssh远程连接Linux服务器登录时密码password无法输入

问题 最近在用Vscode远程连接Linux服务器时&#xff0c;在终端提示输入密码password的时候用键盘输入没有反应。 以为是键盘坏了&#xff0c;然后尝试复制粘贴没有用。 后来找到了原因以及解决方法&#xff0c;感谢原帖作者&#xff08;原贴链接粘在下面&#xff09; 原因 …

2024.7.16日 最新版 docker cuda container tookit下载!

nvidia官方指导 https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html 其实就是这几个命令&#xff0c;但是有墙&#xff1a; curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/shar…

知识图谱研究综述笔记

推荐导读&#xff1a;知识图谱Knowledge Graph Embeddings 论文标题:A Survey on Knowledge Graphs:Representation, Acquisition and Applications发表期刊:IEEE TRANSACTIONS ON NEURAL NETWORKS AND LEARNING SYSTEMS, 2021本文作者&#xff1a;Shaoxiong Ji, Shirui Pan, M…

[A-04] ARMv8/ARMv9-Cache的相关策略

ver0.3 前言 前面我们已经通过三篇文章反反复复的讲Cache的概念、结构、架构&#xff0c;相信大家对Cache已经大概有了初步的了解。这里简单归纳一下: (1) Cache从硬件视角看&#xff0c;是连接PE-Core和主存的一种存储介质&#xff0c;存储的数据是主存中数据的副本&#xf…

精选电脑视频录制软件,这3款让录制更高效!

随着信息技术的飞速发展&#xff0c;电脑视频录制软件在日常生活和工作中的应用越来越广泛。无论是教学演示、游戏录制、网络会议&#xff0c;还是个人创作&#xff0c;视频录制都扮演着不可或缺的角色。本文将详细介绍3款电脑视频录制软件&#xff0c;旨在帮助用户选择最适合自…

AI写作辅助工具,如何避免学术不端?

正如常言道&#xff0c;水边行走难免沾湿——虽然这个比喻并不完全适用——AI创作依赖于现有数据&#xff0c;其生成内容多基于已有素材。目前AI的智能尚未达到人类思维的复杂性&#xff0c;创作过程仍显机械。因此&#xff0c;AI撰写的文章常带有可辨识的特征。 在学术界&…

ARM功耗管理之功耗数据与功耗收益评估

安全之安全(security)博客目录导读 思考&#xff1a;功耗数据如何测试&#xff1f;功耗曲线&#xff1f;功耗收益评估&#xff1f; UPF的全称是Unified Power Format&#xff0c;其作用是把功耗设计意图&#xff08;power intent&#xff09;传递给EDA工具&#xff0c; 从而帮…

移动UI:任务中心的作用,该如何设计更合理?

任务中心是移动应用中用于展示和管理用户待办任务、提醒事项、用户福利、打卡签到等内容的功能模块。合理设计任务中心可以提升用户体验和工作效率。 以下是一些设计任务中心的合理建议&#xff1a; 1. 易于查看和管理&#xff1a; 任务中心的设计应该使用户能够快速、直观地…

蓝牙信标为什么成了众多企业必要的设备?

蓝牙信标对于很多企业单位或是具有一定危险性的化工厂都是必要的&#xff0c;如此才能保证人员的人身安全&#xff0c;并对管理和环境情况的变化有实时的了解&#xff0c;在出现意外的时候&#xff0c;可以将危害和损失降到最低&#xff0c;而蓝牙信标备受信赖的原因无非就是它…

OrangePi 学习摘录

文章目录 1. 参考2. 开发板 Orange-Pi-CM4 预览3. 烧录 Linux 镜像到 TF 卡中4. 制作桌面版镜像qemu/chroot 5. Armbian6. 编译 1. 参考 淘宝 香橙派官网 Orange-Pi-3B Orange-Pi-CM4 基于docker构建香橙派zero系统构建环境 2. 开发板 Orange-Pi-CM4 预览 3. 烧录 Linux 镜像…

阿里云CDN架构技术(一)

CDN补充 cdn内容分发网络&#xff08;content delivery network&#xff0c;cdn&#xff09; 构建在互联网TCP/IP四层模型之上对用户透明的覆盖网。 该网络通过全球范围内分布式部署边缘服务器&#xff0c;将互联网内容从互联网中心缓存到靠近用户的边缘服务器上&#xff0c;…

嵌入式人工智能(2-树莓派4B开发板硬件环境搭建)

1.硬件开发环境&#xff08;T型板&#xff09; 树莓派4B开发板需要搭配面包板&#xff0c;T型板将40个GPIO口引出&#xff0c;再将T型板插到面包板上面。这个地方需要注意插接的方向&#xff0c;由于插树莓派引脚的排线没有防呆设计&#xff0c;因此&#xff0c;请注意方向&am…

【轻松拿捏】Java都有哪些特性?

Java都有哪些特性&#xff1f; 1. 面向对象 2. 平台无关性 3. 简单性 4. 安全性 5. 内存管理 6. 多线程 7. 动态性 8. 分布式计算 9. 健壮性 10. 高性能 11. 丰富的标准库 12. 社区支持和生态系统 13. 可移植性 14. 安全性和强类型 15. 模块化和可扩展性 总结 …

线上CPU 100%问题排查

1、安装jdk工具 jstack 2、使用top命令查看占用CPU高的进程 3、使用命令 top -Hp %ThreadId 查看进程中具体线程使用CPU情况 4、使用命令 jstack -l %ThreadId > cc.txt 保存线程堆栈信息 5、分析具体线程ID的堆栈&#xff08;16进制&#xff09;&#xff0c;看看是否有BL…