本篇参考老罗的实例进行总结。老罗写六篇,层层嵌套,他告诉了我们流程,但没有说编程思想,所以,即使知道怎么做也很快会忘调,因此打算总结下每层之间是怎么调用的,以加深印象。不对细节进行探讨。细节可以参见老罗的blog:http://blog.csdn.net/luoshengyang/article/details/6567257
老罗的分析是从驱动到应用层的,但我想从app开发者的角度去反思这个流程,我反过来说吧。
Tips:老罗这个例子,太多hello相关的函数和类了,要区分的话,目录是个好东西!要注意当前说的层在哪个目录!我会把它加粗。
Tips2:封装是理清各层关系的关键,除了驱动,上面的app/framework(JNI)/HAL层主要工作都是封装。
应用层->Framwork层->HAL层
问题一.作为app开发者,如果我想调用硬件驱动的一个功能,我要怎么做?
1.先按常规办法,做好UI界面。可以IDE中调试好。
2.在事件触发函数里,调用SystemService,获取底层的服务,并把它转化为aidl接口
- import android.os.IHelloService;
- public class Hello extends Activity implements OnClickListener {
- private IHelloService helloService = null;
- .....
- public void onCreat(Bundle savedInstanceState){
- .....
- helloService = IHelloService.Stub.asInterface( ServiceManager.getService("hello"));
- .....
- }
- }
- public void onClick(View v) {
- .....
- helloService.setVal(val);
- .....
- }
问题二.如果要在SDK源码里测试,有什么要注意?——Android.mk
1.在SDK里,aidl文件,会产生在out/target/common/obj目录下,自己去搜吧(参照http://blog.csdn.net/xzongyuan/article/details/38119551)
2.如果你在Eclipse上写aidl文件,会产生在apk源码目录的gen下。因此,如果要把源码复制到SDK,要把gen目录删掉,不然这个目录会生成aidl相关的java文件,会和第一步生成的产生冲突。
3.在源码目录新增加Android.mk,这样SDK编译的时候,才会把该源码编译进去。例如:可以把自己的测试代码放到:/package/experimental/hello 下,并在该目录新增Android.mk,这点可以查看兄弟目录的文件结构。
Android.mk的文件内容如下:
问题三.要怎样设计一个IHelloService供上层调用?
1.进入到frameworks/base/core/java/android/os目录,新增IHelloService.aidl接口定义文件:
USER-NAME@MACHINE-NAME:~/Android$ cd frameworks/base/core/java/android/os
USER-NAME@MACHINE-NAME:~/Android/frameworks/base/core/java/android/os$ vi IHelloService.aidl
IHelloService.aidl定义了IHelloService接口:
- package android.os;
- interface IHelloService {
- void setVal(int val);
- int getVal();
- }
/framework/base下的Android.mk,可见Android.mk在SDK里面是很重要的,它是个组织文件的Makefile。例子:
返回到frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IHelloService.aidl源文件
- LOCAL_SRC_FILES += /
- ....................................................................
- core/java/android/os/IVibratorService.aidl /
- core/java/android/os/IHelloService.aidl /
- core/java/android/service/urlrenderer/IUrlRendererService.aidl /
- .....................................................................
编译后,会生成 IHelloService.java(就是上面提到的/out/target/common下的目录),这个文件的IHelloService接口,会实现一个Stub子接口,该子接口提供了一个函数,
- public static com.styleflying.AIDL.forActivity asInterface(android.os.IBinder obj)
- {
- if ((obj==null)) {
- return null;
- }
这个函数就是前面提到的供Activity用的asInterface了。
activity里的使用方法如下,把具体的服务调出来了:
- helloService = IHelloService.Stub.asInterface( ServiceManager.getService("hello"));
3.这个IHelloService对象应该放在哪里?
定一个类,继承它,并封装它的函数,最后把它注册到ServiceManager就行了
进入到frameworks/base/services/java/com/android/server目录,新增HelloService.java文件:
- <span><span class="keyword">package</span><span> com.android.server; </span></span><span><span class="keyword">
- import</span><span> android.content.Context; </span></span><span><span></span></span><span><span class="keyword">
- import</span><span> android.os.IHelloService; </span></span><span></span><span><span class="keyword">
- import</span><span> android.util.Slog;
- </span></span>public class HelloService extends IHelloService.Stub {
- private static final String TAG = "HelloService";
- /*封装IHelloService接口的函数*/
- HelloService() {
- init_native();
- }
- public void setVal(int val) {
- setVal_native(val);
- }
- public int getVal() {
- return getVal_native();
- }
- private static native boolean init_native();