Freescale IMX6 Android (6): 向SystemServer中添加Service

简述

前面的博客中,我们直接添加C lib到APK中,然后使用LoadLibrary加载这个库,同时添加一个class来作为中间层,直接使用这个C库中的native函数来控制硬件,这种做法将硬件与APK牢牢绑定,如果有多个APP来访问同一个硬件就会出现问题,代码也会有很多的重复,在Android中,我们使用Android的SystemServer向ServiceManager来将硬件的功能添加为一个服务,这样当一个APP需要使用硬件的时候就向SystemServer发出请求service服务,然后由ServiceMnager统一提供服务,提供统一的接口与硬件控制,即相当于多添加了一层,从而实现解耦。

详细原理

先看下图(图片来源于韦东山的Android视频资料)中的③②①,按照顺序:

  1. SystemServer会加载Cpp lib
  2. 在JNI_OnLoad中注册各个Service,SystemServer向ServiceManager添加服务
  3. 这些service就包括像串口/LED等硬件相关的服务


而使用的时候,就是7~5步骤:

  1. AddService:SystemServer向ServiceManager添加服务addServeice
  2. getservice:通过getservice来从SystemServer注册了的service中获取服务所具有的功能,例如ledctrl
  3. 使用Service的方法:APP使用一个Interface(即以i开头的对象)来使用service提供的功能,将服务请求到SystemServer去

APP/SystemServer/ServiceManager三者都是通过Bindler来通讯。

添加Service与使用Service的步骤

添加serviceAIDL文件,生成Interface java文件

因为系统中其他都aidl文件都放在frameworks/base/core/java/android/os下,所有我们也参考其他的文件添加一个ILedService.aidl:


可以看到这个interface前面有个@hide的修饰,表明是个hide class。

同时还需要将此aidl文件添加到Android.mk(Makefile)中:


这个这个Android.mk位于frameworks/base/,编译后就会生成一个ILedService.java

添加service的实现cpp

里面定义好了来调用这个native函数的java class名字为com_android_server_LedService:


还需要添加到编译中:

添加LedService.java文件

前面有了native c/cpp的实现,接下来就需要用JNI来调用native方法了,因此需要添加LedService.java(frameworks/base/services/java/com/android/server/LedService.java)文件:


内容很简单:

  • 声明了native函数
  • 在构造函数中调用open打开设备

上层的Android.mk会自动将java文件添加到Android编译中,不需要自己添加。

让SystemServer启动的时候加载service


这个是因为SystemServer进程启动的时候会去调用LoadLibrary去加载各个库,这个加载的过程就在OnLoad.cpp中。

添加Service到ServiceManager中

这个是在SystemServer中完成的:

LED App中使用添加的Service

到了最后就可以使用这些服务了,但是要使用之前还需要添加包含了LedService的模块,这个模块其实是framework,但是因为我们是java,而framework属于dex格式,因此我们需要添加jar格式的包,这个包编译完成后,位于:

out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar

因此在APP中添加此模块:


并将此模块添加到app的依赖中:


然后在代码中导入Interface与ServiceManager,并使用Service:


这种添加Service到ServiceManager方法的问题

现在我们依然将硬件相关的操作放到了一个cpp中,而这个cpp会编译到系统中,因此如果对硬件的操作有变更,我们就需要修改这个文件,修改了这个文件,那么就需要将整个Android系统重新编译,因此图片中还有一个步骤④,这个就是将硬件相关的东西放在一个HAL层,这样子就避免了修改一个文件就需要编译整个系统,同时也可以不放出与硬件相关的源码而仅仅给出一个HAL相关的库(保密)。

遇到的问题

multidex问题

因为包含了framework的classes.jar,而这个jar中有超过65K个的方法,因此就需要开启multidex。


同时还需要更改xml文件:


并对gradle resync。

jar不匹配的问题

如果重新编译了Android classes.jar但是在APP中依旧使用的是老的,那么会出现一些奇怪的问题:


此时需要先将老的移除掉然后重新添加,或者直接在app的workspace中替换新的。

javaHeap size的配置

4 comments

  1. 樓主,您好

    我照您的方法但app有以下訊息,您知道是怎麼回事嗎?

    01-02 08:00:16.740 3198-3198/? D/dalvikvm: Late-enabling CheckJNI
    01-02 08:00:16.910 3198-3198/com.hexiongjun.led I/MultiDex: VM with version 1.6.0 does not have multidex support
    01-02 08:00:16.910 3198-3198/com.hexiongjun.led I/MultiDex: install
    01-02 08:00:16.910 3198-3198/com.hexiongjun.led I/MultiDex: MultiDexExtractor.load(/data/app/com.hexiongjun.led-1.apk, false)
    01-02 08:00:16.920 3198-3198/com.hexiongjun.led I/MultiDex: loading existing secondary dex files
    01-02 08:00:16.920 3198-3198/com.hexiongjun.led I/MultiDex: load found 1 secondary dex files
    01-02 08:00:16.930 3198-3198/com.hexiongjun.led I/MultiDex: install done
    01-02 08:00:17.110 3198-3198/com.hexiongjun.led I/dalvikvm: Could not find method android.content.res.TypedArray.getChangingConfigurations, referenced from method android.support.v7.internal.widget.TintTypedArray.getChangingConfigurations
    01-02 08:00:17.110 3198-3198/com.hexiongjun.led W/dalvikvm: VFY: unable to resolve virtual method 9889: Landroid/content/res/TypedArray;.getChangingConfigurations ()I
    01-02 08:00:17.110 3198-3198/com.hexiongjun.led D/dalvikvm: VFY: replacing opcode 0x6e at 0x0002
    01-02 08:00:17.110 3198-3198/com.hexiongjun.led I/dalvikvm: Could not find method android.content.res.TypedArray.getType, referenced from method android.support.v7.internal.widget.TintTypedArray.getType
    01-02 08:00:17.110 3198-3198/com.hexiongjun.led W/dalvikvm: VFY: unable to resolve virtual method 9912: Landroid/content/res/TypedArray;.getType (I)I
    01-02 08:00:17.110 3198-3198/com.hexiongjun.led D/dalvikvm: VFY: replacing opcode 0x6e at 0x0002
    01-02 08:00:17.120 3198-3198/com.hexiongjun.led I/dalvikvm: Could not find method android.widget.LinearLayout$LayoutParams., referenced from method android.support.design.widget.AppBarLayout$LayoutParams.
    01-02 08:00:17.120 3198-3198/com.hexiongjun.led W/dalvikvm: VFY: unable to resolve direct method 53794: Landroid/widget/LinearLayout$LayoutParams;. (Landroid/widget/LinearLayout$LayoutParams;)V
    01-02 08:00:17.120 3198-3198/com.hexiongjun.led D/dalvikvm: VFY: replacing opcode 0x70 at 0x0000
    01-02 08:00:17.120 3198-3198/com.hexiongjun.led I/dalvikvm: Could not find method android.widget.LinearLayout$LayoutParams., referenced from method android.support.design.widget.AppBarLayout$LayoutParams.
    01-02 08:00:17.120 3198-3198/com.hexiongjun.led W/dalvikvm: VFY: unable to resolve direct method 53794: Landroid/widget/LinearLayout$LayoutParams;. (Landroid/widget/LinearLayout$LayoutParams;)V
    01-02 08:00:17.120 3198-3198/com.hexiongjun.led D/dalvikvm: VFY: replacing opcode 0x70 at 0x0000
    01-02 08:00:17.160 3198-3198/com.hexiongjun.led D/dalvikvm: GC_FOR_ALLOC freed 332K, 13% free 2759K/3148K, paused 14ms, total 14ms
    01-02 08:00:17.270 3198-3198/com.hexiongjun.led D/libEGL: loaded /system/lib/egl/libEGL_VIVANTE.so
    01-02 08:00:17.290 3198-3198/com.hexiongjun.led D/libEGL: loaded /system/lib/egl/libGLESv1_CM_VIVANTE.so
    01-02 08:00:17.360 3198-3198/com.hexiongjun.led D/libEGL: loaded /system/lib/egl/libGLESv2_VIVANTE.so
    01-02 08:00:17.430 3198-3198/com.hexiongjun.led D/OpenGLRenderer: Enabling debug mode 0
    01-02 08:00:17.480 3198-3198/com.hexiongjun.led W/dalvikvm: method Landroid/support/v7/internal/widget/ListViewCompat;.lookForSelectablePosition incorrectly overrides package-private method with same name in Landroid/widget/ListView;
    01-02 08:00:42.920 3198-3198/com.hexiongjun.led W/System.err: java.lang.NullPointerException
    01-02 08:00:42.920 3198-3198/com.hexiongjun.led W/System.err: at com.hexiongjun.led.MainActivity$2.onClick(MainActivity.java:61)
    01-02 08:00:42.920 3198-3198/com.hexiongjun.led W/System.err: at android.view.View.performClick(View.java:4240)
    01-02 08:00:42.920 3198-3198/com.hexiongjun.led W/System.err: at android.view.View$PerformClick.run(View.java:17721)
    01-02 08:00:42.920 3198-3198/com.hexiongjun.led W/System.err: at android.os.Handler.handleCallback(Handler.java:730)
    01-02 08:00:42.920 3198-3198/com.hexiongjun.led W/System.err: at android.os.Handler.dispatchMessage(Handler.java:92)
    01-02 08:00:42.920 3198-3198/com.hexiongjun.led W/System.err: at android.os.Looper.loop(Looper.java:137)
    01-02 08:00:42.920 3198-3198/com.hexiongjun.led W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5103)
    01-02 08:00:42.930 3198-3198/com.hexiongjun.led W/System.err: at java.lang.reflect.Method.invokeNative(Native Method)
    01-02 08:00:42.930 3198-3198/com.hexiongjun.led W/System.err: at java.lang.reflect.Method.invoke(Method.java:525)
    01-02 08:00:42.930 3198-3198/com.hexiongjun.led W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
    01-02 08:00:42.930 3198-3198/com.hexiongjun.led W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    01-02 08:00:42.930 3198-3198/com.hexiongjun.led W/System.err: at dalvik.system.NativeStart.main(Native Method)

    1. 看到里面的Log有空指针访问:01-02 08:00:42.920 3198-3198/com.hexiongjun.led W/System.err: java.lang.NullPointerException
      而且是调到native中出现的问题?

      建议:
      1. 先确定一下native调用是否有问题
      2. 确定native(com_android_server_LedService.cpp)中打开的设备文件(”/sys/class/leds/led%d/brightness”)是否存在,因为native的open在对象创建的时候就被调用了(native_ledOpen())

      如果没有这个设备文件,那么更改一下Kernel。

  2. 樓主,您好

    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: java.lang.NullPointerException
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at com.hexiongjun.led.MainActivity$2.onClick(MainActivity.java:73)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at android.view.View.performClick(View.java:4240)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at android.view.View$PerformClick.run(View.java:17721)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at android.os.Handler.handleCallback(Handler.java:730)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at android.os.Handler.dispatchMessage(Handler.java:92)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at android.os.Looper.loop(Looper.java:137)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5103)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at java.lang.reflect.Method.invokeNative(Native Method)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at java.lang.reflect.Method.invoke(Method.java:525)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    01-02 08:05:17.690 3499-3499/com.hexiongjun.led W/System.err: at dalvik.system.NativeStart.main(Native Method)
    01-02 08:05:17.700 2439-2736/? W/audio_hw_primary: card 0, port 0 device 0x2
    01-02 08:05:17.700 2439-2736/? W/audio_hw_primary: rate 44100, channel 2 period_size 0xc0
    01-02 08:05:20.780 2439-2759/? W/audio_hw_primary: do_out_standby… 1094250200

    不曉得是不是因為有加了toolbox的main function才導致

    如果在Service這裡增加ledctrl function,是不是toolbox那邊的ledctrl.c要註解掉呢?
    (Android.mk要註解掉嗎?)

    謝謝~

    1. 不需要。因为调用流程是:App — > Service –> JNI –> C function, 这里并不涉及到toolbox。
      既然是System Error,那么肯定就是从System logger中打印出来的,所以还是先考虑这边的。
      toolbox不过是一个命令行工具,是不会将log输出到android logger中的,一般都是直接到STDOUT。

Leave a Reply

Your email address will not be published. Required fields are marked *