Android应用程序访问linux驱动第三步:实现并向系统注册Service
来源:互联网 发布:电气控制柜的设计软件 编辑:程序博客网 时间:2024/05/21 09:50
应用程序访问service设计到了进程间的通信,这要求我们使用(Android Interface definition language)来描述我们的service提供的接口,然后应用程序就可以通过binder来访问service 了。所以,我们先从aidl开始,逐步搭建我们的service层。
一.aidl
在Android系统中,硬件服务一般是运行在一个独立的进程中为各种应用程序提供服务。因此,调用这些硬件服务的应用程序与这些硬件服务之间的通信需要通过代理来进行。为此,我们要先定义好通信接口。进入到frameworks/base/core/java/android/os/目录下新建IHelloTestService.aidl文件,用来描述我们的service提供的接口:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
我们的service只提供两个方法,一个写字符串,另一个读字符串。返回到frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IHelloTestService.aidl源文件:
LOCAL_SRC_FILES += \
core/java/android/os/IHelloTestService.aidl \
编译IHelloTestService.aidl接口:mmm frameworks/base 这样,就会根据IHelloService.aidl生成相应的IHelloTestService.Stub接口。会在./out/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/os/目录下生成IHelloTestService.java文件。IHelloTestService.java文件中实现了使用binder通信的一些方法,同时还包含了我们在接口中定义的两个方法。接下来,我们需要实现这两个方法。
二.HelloTestService.java
在frameworks/base/services/java/com/android/server/下新建HelloTestService.java文件,也就是创建HelloTestService类,这个类继承了IHelloTestService中的Stub内部类,我们需要复写其中的我们在aidl中定义的两个方法。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
这个类中是java中的类,java是不能直接访问C/C++代码的,必须使用jni来实现。因此,我们在这里简单调用jni中对应的方法即可。HelloTestService主要是通过调用JNI方法init_native、wirteString_native和readString_native(见在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口一文)来提供硬件服务。
三.实现jni访问HAL
进入到frameworks/base/services/jni/目录,新建com_android_server_HelloService.cpp文件:在com_android_server_HelloTestService.cpp文件中,实现JNI方法。注意文件的命令方法,com_android_server前缀表示的是包名,表示硬件服务HelloTestService是放在frameworks/base/services/java目录下的com/android/server目录的,即存在一个命令为com.android.server.HelloTestService的类。这里HelloTestService类是一个提供Java接口的硬件访问服务类。
备注:在java对应native代码中,就可以使用C/C++来访问C/C++代码了,回想下我们在上节测试hal层代码时写的测试代码,这部分代码将与之类似,只不过,因为这部分代码需要供java层调用,所以它需要遵寻固定的格式。
jni层代码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
这部分代码中,我们把java层传下来的字符串转换为c++的char *字符数组,然后通过HAL层把它写入linux驱动。然后把从linux驱动中读出来的字符串转换为java层的字符串并返回给java层。
3.1向HelloTestService中注册本地方法
修改frameworks/base/services/jni/目录下的onload.cpp文件,首先在namespace android增加register_android_server_HelloTestService函数声明:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
然后再onload.cpp中调用register_android_server_HelloTestService方法向java层的HelloTestService类注册我们的native方法:
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
3.2编译
修改/frameworks/base/services/jni/目录下的Android.mk:
添加一行:
- 1
- 1
这样就可以编译我们的native代码了,此时可以尝试编译并修改错误。至此,本地的代码会在onload.cpp中完成向java层对应类的注册,同时我们可以编译我们的service,使用mmm framework/base/service即可。我们已经完成了service层代码的编写,但系统还不会使用我们的service,所以,接下来我们要向系统注册我们的服务。
四.向系统注册我们的java服务
系统在启动的时候,会使用SystemServer类启动或者注册系统服务,所以我们要在其中注册我们的服务。
进入frameworks/base/services/java/com/android/server/SystemServer.java中在ServerThread::run函数中增加加载HelloService的代码,最后注册我们的服务就好了,使用ServiceManager.addService即可:
public void run() {
...................................................................................
(贴出要添加前面示例代码,方便定位。)
try {
Slog.i(TAG, "DiskStats Service");
ServiceManager.addService("diskstats", new DiskStatsService(context));
} catch (Throwable e) {
Slog.e(TAG, "Failure starting DiskStats Service",e);
} (贴出要添加前面示例代码,方便定位。)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
然后再执行mmm frameworks/base/services/ 进行编译。编译完成后,使用make snod命令重新打包system.img,然后重写烧写system.img,这样,系统中就有了我们的服务了。然而事情往往没有想想中顺利,我们需要解决一些问题。
五.解决问题
前面贴出来的代码已经是经过测试的代码,可以正常使用,这里还是把我在实现service的过程中遇到的问题总结一下。
注意:我们在前面的文章中测试linux驱动和HAL层代码的时候都是动态安装linux驱动的,这里因为我们在android启动的时候就注册我们的service,所以,驱动必须编译进linux kernel。而且,我们在android应用程序访问Linux驱动第二步-实现并测试hardware层
中编译出来的hellotest.default.so文件必须拷贝到/system/lib/hw目录下。
5.1系统无法成功启动
重新烧写完系统后发现系统无法成功启动,Log如下:
- 1
- 2
- 3
- 1
- 2
- 3
这个问题是由于之前代码"(Ljava/lang/String;)I"
中遗忘了”;”造成的,加上“;”即可解决。
5.2解决devie无法打开
从开机Log可以看到,/dev/hello无法打开:
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
这是因为我们没有访问/dev/hello权限问题导致的解决方法:打开Android源代码工程目录下,进入到system/core/rootdir目录,里面有一个名为ueventd.rc文件,往里面添加一行:
/dev/hello 0666 root root
最后,我们可以在开机Log中看到
- 1
- 2
- 3
- 1
- 2
- 3
等LOG,说明我们的服务已经成功完成注册。
- Android应用程序访问linux驱动第三步:实现并向系统注册Service
- Android应用程序访问linux驱动第三步:实现并向系统注册Service
- Android应用程序访问linux驱动第四步:实现android应用程序
- Android应用程序访问linux驱动第二步:实现并测试hardware层
- Android应用程序访问linux驱动第五步:回顾hw_get_module
- Android应用程序访问linux驱动第一步:实现并测试Linux驱动
- Android Binder Mechanism (3) -- 如何向系统注册Service
- Android Binder Mechanism (3) -- 如何向系统注册Service
- Android Binder Mechanism (3) -- 如何向系统注册Service
- Service与Android系统实现-- 应用程序里的Service
- JNI开发第三步:20130801_NDK_JNI的.so文件开发-安卓访问LINUX驱动
- 浅谈Android system_service 注册Service、APP获取并访问服务(PMS:PowerManagerService)为例
- 不同数据库驱动的加载并向DriverManager注册
- Service与Android系统实现(1)-- 应用程序里的Service
- Service与Android系统实现(1)-- 应用程序里的Service
- Service与Android系统实现(1)-- 应用程序里的Service
- Service与Android系统实现(1)-- 应用程序里的Service
- Service与Android系统实现(1)-- 应用程序里的Service(二)
- socket阻塞与非阻塞,同步与异步、I/O模型------非常值得一看!
- ZYNQ系统中实现FAT32文件系统的SD卡读写之四 经验总结
- 最新100个微信小程序
- Apriori算法初使用
- 【大数据部落】用R挖掘Twitter数据
- Android应用程序访问linux驱动第三步:实现并向系统注册Service
- 微信小程序推荐大全之101~200个
- CentOS 7 安装Kubernetes(1)--手动部署节点
- arm汇编程序调用C函数之参数传递
- 一分钟了解“Matlab的squeeze函数”
- Javascript引擎内部的三种抽象操作
- 正向代理与反向代理、负载均衡
- 解决浏览器登陆GitHub官网提示404的问题
- 两款Docker管理UI:DockerUI & Shipyard