Freescale IMX6 Android (6): 向ServerManager中添加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:

package android.os;

/** {@hide} */
interface ILedService
{
    int ledCtrl(int which, int status);
}

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

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

 $ git diff Android.mk
diff --git a/Android.mk b/Android.mk
index 151621c..7bde511 100644
--- a/Android.mk
+++ b/Android.mk
@@ -150,6 +150,7 @@ LOCAL_SRC_FILES += \
        core/java/android/os/IUpdateLock.aidl \
        core/java/android/os/IUserManager.aidl \
        core/java/android/os/IVibratorService.aidl \
+       core/java/android/os/ILedService.aidl \
        core/java/android/service/notification/INotificationListener.aidl \
        core/java/android/service/dreams/IDreamManager.aidl \
        core/java/android/service/dreams/IDreamService.aidl \

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


添加service的实现cpp

#define LOG_TAG "LedService"

#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"

#include <utils/misc.h>
#include <utils/Log.h>
//#include <hardware_legacy/led.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

namespace android
{

#define ALOGI printf
#define LED_NUM 3
int leds_fd[LED_NUM];
char path_buff[255];

static jint ledCtrl(JNIEnv *env, jobject clazz, jint which, jint status)
{
    int ret = -1;
    if(status == 1) {
        ret = write(leds_fd[which], "255", 3);
    } else {
        ret = write(leds_fd[which], "0", 1);
    }
    if(ret < 0){
        return -1;
    }
    ALOGI("Native ctrl fd = [%d]\n", which);
    return 0;
}

static jint ledOpen(JNIEnv *env, jobject clazz)
{
    int i = 0;
    for(i=0; i<LED_NUM; i++){
        sprintf(path_buff, "/sys/class/leds/led%d/brightness", i);
        printf("path:%s\n",path_buff);
        leds_fd[i] = open(path_buff, O_RDWR);

        if(leds_fd[i] < 0){
            ALOGI("led%d: %s, open failed\n", i, path_buff);
            return -1;
        } else {
            ALOGI("led%d: %s, open success\n", i, path_buff);
        }
    }
    return 0;
}

static void ledClose(JNIEnv *env, jobject clazz)
{
    int i = 0;
    for(i=0; i< LED_NUM; i++){
        close(leds_fd[i]);
    }
}

static JNINativeMethod method_table[] = {
    { "native_ledCtrl", "(II)I", (void*)ledCtrl },
    { "native_ledClose", "()V", (void*)ledClose },
    { "native_ledOpen", "()I", (void*)ledOpen }
};

int register_android_server_LedService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/LedService",
            method_table, NELEM(method_table));
}

};

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

jniRegisterNativeMethods(env, "com/android/server/LedService",
            method_table, NELEM(method_table));

还需要添加到编译中:

$ git diff services/jni/Android.mk
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index b313d48..fb359cb 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -14,6 +14,7 @@ LOCAL_SRC_FILES:= \
     com_android_server_UsbDeviceManager.cpp \
     com_android_server_UsbHostManager.cpp \
     com_android_server_VibratorService.cpp \
+    com_android_server_LedService.cpp \
     com_android_server_location_GpsLocationProvider.cpp \
     com_android_server_connectivity_Vpn.cpp \
     onload.cpp


添加LedService.java文件

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

package com.android.server;

import android.os.ILedService;

/**
 * Created by hexiongjun on 12/9/15.
 * Function:
 *  Call Native C function to control hardware
 */
public class LedService extends ILedService.Stub{
    private static final String TAG = "LedService";
    public int ledCtrl(int which, int status) throws android.os.RemoteException {
        return native_ledCtrl(which, status);
    }
    public void LedService(){
        native_ledOpen();

    }
    // Declare the function
    public native static int native_ledCtrl(int which, int status);
    public native static int native_ledOpen();
    public native static void native_ledClose();
}

内容很简单:

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

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


让SystemServer启动的时候加载service

 $ git diff services/jni/onload.cpp
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 423ebd1..83721fe 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -31,6 +31,8 @@ int register_android_server_SerialService(JNIEnv* env);
 int register_android_server_UsbDeviceManager(JNIEnv* env);
 int register_android_server_UsbHostManager(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
+// From com_android_server_LedService.cpp
+int register_android_server_LedService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
 int register_android_server_location_GpsLocationProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
@@ -60,6 +62,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
     register_android_server_UsbDeviceManager(env);
     register_android_server_UsbHostManager(env);
     register_android_server_VibratorService(env);
+    register_android_server_LedService(env);
     register_android_server_SystemServer(env);
     register_android_server_location_GpsLocationProvider(env);
     register_android_server_connectivity_Vpn(env);

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


添加Service到ServiceManager中

这个是在SystemServer中完成的:

$ git diff services/java/com/android/server/SystemServer.java
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9455017..1ccf63a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -129,6 +129,7 @@ class ServerThread extends Thread {
         PowerManagerService power = null;
         DisplayManagerService display = null;
         BatteryService battery = null;
+        LedService led = null;
         VibratorService vibrator = null;
         AlarmManagerService alarm = null;
         MountService mountService = null;
@@ -288,6 +289,11 @@ class ServerThread extends Thread {
             battery = new BatteryService(context, lights);
             ServiceManager.addService("battery", battery);
 
+            //Add the led service to SystemServer, so others can use
+            Slog.i(TAG, "Led Service");
+            led = new LedService();
+            ServiceManager.addService("led", led);
+
             Slog.i(TAG, "Vibrator Service");
             vibrator = new VibratorService(context);
             ServiceManager.addService("vibrator", vibrator);

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。

 $ git diff app/build.gradle
diff --git a/app/build.gradle b/app/build.gradle
index 131397f..82a2a62 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -10,6 +10,12 @@ android {
         targetSdkVersion 22
         versionCode 1
         versionName "1.0"
+
+        //Enable multidex
+        multiDexEnabled true
+    }
+    dexOptions {
+        javaMaxHeapSize "4g"
     }
     sourceSets{
         main {
@@ -29,4 +35,6 @@ dependencies {
     testCompile 'junit:junit:4.12'
     compile 'com.android.support:appcompat-v7:22.2.1'
     compile 'com.android.support:design:22.2.1'
+    compile project(':classes')
+    compile 'com.android.support:multidex:1.0.0'
 }

同时还需要更改xml文件:

$ git diff app/src/main/AndroidManifest.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a77e7a1..1504514 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
     package="com.hexiongjun.led">
 
     <application
+        android:name="android.support.multidex.MultiDexApplication"
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"

并对gradle resync。

jar不匹配的问题

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


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


javaHeap size的配置


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值