有一天在群里聊天的时候,有人提出一个问题,怎样才能作到HAL层访问JAVA层的接口?恰好我不会,因此作了一点研究。html
以前的文章末尾部分说过了service call 能够用来调试系统的binder服务。 传送门: Android native进程间通讯实例-binder篇之——简单的单工通讯java
此次能够用到这个命令了!android
1. 随机选取一个java层的服务。shell
adb shell 中输入命令 service list,选取一个服务来作研究,此次看中的是 textservices, 注意第一个服务 bysysui 后面的 "[ ]" 里面没有内容,不能选取这样的服务来作此次的研究。数组
2. 搜寻这个服务相关的源码。函数
frameworks/base/services/core/java/com/android/server/TextServicesManagerService.javaui
frameworks/base/core/java/com/android/internal/textservice/ITextServicesManager.aidlthis
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/textservice/ITextServicesManager.javaspa
3. 选择一个接口用于被 HAL 层的代码访问3d
能够知道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 层服务的简单例子就讲解到这里,但愿你们看完之后可以举一反三,在这个例子上面获得启发。
但愿读者多多吐槽,咱们一块儿共同进步!!
原文出处:https://www.cnblogs.com/songsongman/p/11100760.html