专栏首页编程入门之C语言Android native进程间通信实例-binder篇之——HAL层访问JAVA层的服务

Android native进程间通信实例-binder篇之——HAL层访问JAVA层的服务

有一天在群里聊天的时候,有人提出一个问题,怎样才能做到HAL层访问JAVA层的接口?刚好我不会,所以做了一点研究。

之前的文章末尾部分说过了service call 可以用来调试系统的binder服务。 传送门: Android native进程间通信实例-binder篇之——简单的单工通信

这次可以用到这个命令了!

1. 随机选取一个java层的服务。

adb shell 中输入命令 service list,选取一个服务来做研究,这次看中的是 textservices, 注意第一个服务 bysysui 后面的 "[ ]" 里面没有内容,不能选取这样的服务来做这次的研究。

2. 搜寻这个服务相关的源码。

frameworks/base/services/core/java/com/android/server/TextServicesManagerService.java

frameworks/base/core/java/com/android/internal/textservice/ITextServicesManager.aidl

out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/textservice/ITextServicesManager.java

3. 选择一个接口用于被 HAL 层的代码访问

可以知道TextServicesManagerService.java 中 有一行 public class TextServicesManagerService extends ITextServicesManager.Stub,

所以我从 ITextServicesManager.aidl 来选择要访问的接口, 这次选的就是 boolean isSpellCheckerEnabled(); 这个函数应该就是返回一个bool变量而已,越简单越好。

4. 搜寻 binder 中 transact 需要输入的 code

因为吧啦吧啦的原因(可以自行去别的博文搜索原理,本系列博文侧重实际操作),所以在out目录下可以获取到每个服务中各个接口访问锁需要传入的code。

在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/textservice/ITextServicesManager.java中可以发现熟悉的onTransact接口,

同时发现调用 sSpellCheckerEnabled 的code为TRANSACTION_isSpellCheckerEnabled,

它的定义是:static final int TRANSACTION_isSpellCheckerEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);

因为android.os.IBinder.FIRST_CALL_TRANSACTION的值是1, 所以可知code为 8

5. 使用service call 来撩一下 isSpellCheckerEnabled

可以看到Parcel有两个值,第一个是00000000,第二个是00000001.

再看看ITextServicesManager.java中TRANSACTION_isSpellCheckerEnabled这个code的处理,果然write了两次,而第二次writeInt的值就是我们需要获取的bool值了!

ITextServicesManager.java

case TRANSACTION_isSpellCheckerEnabled:
{
    data.enforceInterface(DESCRIPTOR);
    boolean _result = this.isSpellCheckerEnabled();
    reply.writeNoException();
    reply.writeInt(((_result)?(1):(0)));
    return true;
}

按照之前分析的方法,传送门:Android native进程间通信实例-binder篇之——用parcel传输数组

1. 首先data.enforceInterface 传进去了一个组字符串 private static final java.lang.String DESCRIPTOR = "com.android.internal.textservice.ITextServicesManager";

感觉这组字符串是和校验有关了,查看了Parcel.cpp 源码, 发现enforceInterface果然是对比字符串用的,在这个接口的上面有个接口名字叫做 writeInterfaceToken,

所以到时候要用 writeInterfaceToken 来写这组字符串用于比对校验。

2. writeNoException 和 writeInt 最终调用的是 Parcel.cpp 里面writeInt32,所以reply部分要 readInt32 两次。

6. HAL层代码怎么写

就直接在之前写的mybinderclient.cpp 上面贴源码吧transct 前写校验字符串,然后传入code 值为8,最后readInt32 两次,第二次就是要读取的JAVA 层服务isSpellCheckerEnabled 的值啦!

#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/IInterface.h>

#include<stdio.h>

#define LOG_TAG "binderclient"

using namespace android;


int main(int argc, char** argv)
{
    static  int TRANSACTION_isSpellCheckerEnabled = (/*android.os.IBinder.FIRST_CALL_TRANSACTION*/1 + 7);

    sp<IBinder> ITextServicesBinder = defaultServiceManager()->getService(String16("textservices"));

    Parcel ITextServicesData, ITextServicesReply;

    ITextServicesData.writeInterfaceToken(String16("com.android.internal.textservice.ITextServicesManager"));
    
    ITextServicesBinder->transact(TRANSACTION_isSpellCheckerEnabled, ITextServicesData, &ITextServicesReply);

    int ret = ITextServicesReply.readInt32();
    int ret2 = ITextServicesReply.readInt32();

    printf("ret = %d, isSpellCheckerEnabled = %d\n", ret, ret2);

    return 0;
}

执行结果:

这次在HAL层通过binder 访问 JAVA 层服务的简单例子就讲解到这里,希望大家看完以后能够触类旁通,在这个例子上面得到启发。

希望读者多多吐槽,我们一起共同进步!!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android native进程间通信实例-binder篇之——用parcel传输数组

    和之前稍微不同,这次要稍微分析一下 Parce.cpp 和 android_os_Parcel.cp p的源码,为的是能够掌握调试技巧,后续传输其它类型数据就...

    啊源股
  • Android native进程间通信实例-binder结合共享内存

      在android源码的驱动目录下,一般会有共享内存的相关实现源码,目录是:kernel\drivers\staging\android\ashmem.c。但...

    啊源股
  • 解决多类开机弹框问题

    生活使用电脑中,经常由于安装某些程序的失误导致电脑开机的时候会弹出一些对话框,对话框的内容大多都是“某某dll安装不正常”、“xx 内存writen错误”等等,...

    啊源股
  • 使用ListView自定义布局

    ListView这个控件实际上是很难用的,就是因为它很多细节可以优化,效率就是比较重要的一点.下面我们来优化下它的效率:

    Dream城堡
  • C#并发编程之异步编程(二)

    前面一篇文章介绍了异步编程的基本内容,同时也简要说明了async和await的一些用法。本篇文章将对async和await这两个关键字进行深入探讨,研究其中的运...

    Edison.Ma
  • Android动态添加Fragment

    Dream城堡
  • Android Source Generator错误:无法找到基本名称xxx的包

    File > Project Structure > facets > 添加Android-Gradle > 关闭并重新打开项目并重建.

    lollipop72
  • 【已解决】IDEA 2020.3 java.lang.UnsupportedClassVersionError

    我程序用的是 JDK8,看报错就是编译和运行使用的 JDK 版本不一致导致的,刚开始以为是 IDEA 配置的编译器版本问题,于是把所有的能设置的地方全都检查了一...

    星尘的一个朋友
  • Linux下java和javac版本不同(设置用户默认的java版本)解决方法

    我的Ubuntu下安装了OpenJDK和Oracle的JDK,然后我在用户自己的配置文件(~./profile)中设置JAVA_HOME(24到28行),

    卡尔曼和玻尔兹曼谁曼
  • Android调用OpenCV2.4.10实现二维码区域定位

    Android上使调用OpenCV 2.4.10 实现二维码区域定位(Z-xing 码),该文章主要用于笔者自己学习中的总结,暂贴出代码部分,待以后有时间再补充...

    砸漏

扫码关注云+社区

领取腾讯云代金券