Android驱动(一)硬件访问服务学习之(二)Android通过硬件访问服务访问硬件

  • 硬件平台:tiny4412
  • 系统:Android  5.0.2
  • 编译器: arm-linux-gcc-4.5.1

上一节我们通过JNI实现了应用程序对硬件的操作,思路是:应用程序中我们申明了本地方法,并通过System.loadLibrary("hardcontrol"); 来加载C库,loadLibrary的同时会调用C库中JNI_OnLoad方法,来注册本地方法,这个时候应用程序就可以通过调用申明的方法来调用C库中对应的方法,从而实现对硬件的访问。然后Android源码中并没有采用这种方式,而是采用了硬件访问服务来操作硬件,具体什么是硬件访问服务呢,这一节我们来详细学习。

首先来看一下硬件访问服务的框图:


一、硬件访问服务实现流程分析:

1、整体思路

(1)硬件访问服务,通过SystemServer来访问硬件,SystemServer通过loadlibrary来加载C库。

(2)同时C库的JNI_OnLoad函数被调用,里面分别调用硬件的JNI函数注册本地方法(JNI调用HAL层)。

(3)SystemServer对每个硬件,构造service,如:vibrator = new VibratorService(context);

(4)然后向ServiceManager里addService。如:ServiceManager.addService("vibrator", vibrator);

(5)应用程序获得service,然后调用里面的方法。

2、具体分析

(1)系统上电后,会执行SystemServer

SystemServer.java有一个主函数,里面调用run方法。

    public static void main(String[] args) {
        new SystemServer().run();
    }

主函数执行run。Run中loadLibrary加载c库:

        // Initialize native services.
        System.loadLibrary("android_servers");
        nativeInit();

android_servers对应的是onload.cpp,里面有JNI_OnLoad函数。loadlibrary的同时JNI_OnLoad被调用

#include "JNIHelp.h"
#include "jni.h"
#include "utils/Log.h"
#include "utils/misc.h"
namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
int register_android_server_AssetAtlasService(JNIEnv* env);
int register_android_server_BatteryStatsService(JNIEnv* env);
int register_android_server_ConsumerIrService(JNIEnv *env);
int register_android_server_InputApplicationHandle(JNIEnv* env);
int register_android_server_InputWindowHandle(JNIEnv* env);
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
int register_android_server_SerialService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_location_GpsLocationProvider(JNIEnv* env);
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
int register_android_server_Watchdog(JNIEnv* env);
};

using namespace android;

extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("GetEnv failed!");
        return result;
    }
    ALOG_ASSERT(env, "Could not retrieve the env!");

    register_android_server_PowerManagerService(env);
    register_android_server_SerialService(env);
    register_android_server_InputApplicationHandle(env);
    register_android_server_InputWindowHandle(env);
    register_android_server_InputManager(env);
    register_android_server_LightsService(env);
    register_android_server_AlarmManagerService(env);
    register_android_server_UsbDeviceManager(env);
    register_android_server_UsbHostManager(env);
    register_android_server_VibratorService(env);
    register_android_server_SystemServer(env);
    register_android_server_location_GpsLocationProvider(env);
    register_android_server_location_FlpHardwareProvider(env);
    register_android_server_connectivity_Vpn(env);
    register_android_server_AssetAtlasService(env);
    register_android_server_ConsumerIrService(env);
    register_android_server_BatteryStatsService(env);
    register_android_server_hdmi_HdmiCecController(env);
    register_android_server_tv_TvInputHal(env);
    register_android_server_PersistentDataBlockService(env);
    register_android_server_fingerprint_FingerprintService(env);
    register_android_server_Watchdog(env);

    return JNI_VERSION_1_4;
}

JNI_OnLoad里面实现注册各个本地服务。

(2) SystemServer.java加载C库后会执行startOtherServices
        // Start services.
        try {
            startBootstrapServices();
            startCoreServices();
            startOtherServices(); 
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        }

(3)startOtherServices会注册服务到ServiceManager里面

            Slog.i(TAG, "Vibrator Service");
            vibrator = new VibratorService(context);
            ServiceManager.addService("vibrator", vibrator);

(4)VibratorService会调用本地方法。

(5)应用程序向ServiceManager查询获得某个服务, 通过获取服务,然后调用服务里面的方法来操作硬件。

二、怎么实现硬件访问服务

(1)需要写一个JNI和HAL。

JNI:com_android_server_VibratorService.cpp (frameworks\base\services\core\jni)里面加载HAL。

HAL:Vibrator.c (hardware\libhardware\modules\vibrator)里面实现对硬件的操作。

(2)修改onload.cpp,添加JNI函数调用。

(3)修改SystemServer.java,new服务,并add到ServiceManager中

(4)想实现上面的newLedService(),必须写出这个服务。实现LedService,里面调用本地方法。

(5)应用程序要获取ILedService接口,供应用程序使用。



三、代码实现

3.1编写aldl文件

实现aldl文件,最简单,给APP使用的接口。

通过.aldl自动生成接口.java文件,实现了进程间的通讯。

参考IVibratorservice.aldl文件编写ILedService.ALDL代码放到,

/android-5.0.2/frameworkds/base/core/java/android/os目录下

(1)ILedService.ALDl

实现与APP直接对接的操作硬件的接口,这个最简单。只需要实现AIDL文件(Android Interface Define Language),其目的是让安卓系统自动帮我们实现对应用JAVA接口文件。PS:可以搜索源码中的例子比如:IVibratorservice.aidl

package android.os;

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

(2)上传AIDL文件 

将AIDL文件上传编译之前,需要先编译整个安卓源码(目前编译4412开发板)。编译完后上传到目录中,But,哪个目录?模仿其它AIDL文件在哪个目录,然后上传到相应的目录。/android-5.0.2/frameworkds/base/core/java/android/os目录下

逐层查找android.mk

(3)修改/android-5.0.2/frameworkds/base/下的Android.mk文件:

增加一行:core/java/android/os/ILedService.aidl\(yy复制当前行 p粘贴)

(4)android-5.0.2/frameworkds/base/下输入mmm  .回车编译当前目录/android-5.0.2/frameworkds/base

(5)编译的结果放在/android-5.0.2/out/下find -name "ILedService.java"。里面实现了

public interface ILedService extends android.os.IInterface

public static abstract class Stub extends android.os.Binder implements android.os.ILedService

public int ledCtrl(int which, int status) throws android.os.RemoteException;

如何使用参考:内核搜索IVibratorService.aidl

    private final IVibratorService mService;

    public SystemVibrator() {
        mService = IVibratorService.Stub.asInterface(
                ServiceManager.getService("vibrator"));
    }。。。

mService.hasVibrator();

(6)ILedService.java这个文件接口如何使用。

先获取Service,然后将其转换为接口对象,然后调用这个接口对象的成员方法。

总结:

l  编写ILedService.aidl文件 ==>编译生成ILedService.java文件

l  app使用:ILedService   iLedService;

 iLedService = ILedService.Stub.asInterface(ServiceManager.getService("Led"))

   调用:iLedService.ledctrl(0,1);

所以用户APP层调用iLedService接口,但是这个接口并不直接操作硬件,iLedService会把服务请求发给LedService

操作硬件的是LedService.java,下面描述这个LedService.java程序怎么编写。注意,这个LedService.java的作用是调用本地Native方法来操作硬件。

3.2编写LedService.java文件

编写LedService.java 参考VibratorService.java

(frameworks/base/services/core/java/com/android/server/LedService.java)

ILedService.Stub类里面有ledCtrl方法,这里也实现。

package com.android.server;
import android.os.ILedService;

public class LedService extends ILedService.Stub {
    private static final String TAG = "LedService";
	/* call native c function to access hardware */
	public int ledCtrl(int which, int status) throws android.os.RemoteException
	{
		return native_ledCtrl(which, status);
	}
	public LedService() {
		native_ledOpen();
	}
	public static native int native_ledOpen();
	public static native void native_ledClose();
	public static native int native_ledCtrl(int which, int status);
}

3.3修改SystemServer.java

(frameworks/base/services/java/com/android/server/SystemServer.java)
startOtherServices:
            Slog.i(TAG, "Vibrator Service");
            vibrator = new VibratorService(context);
            ServiceManager.addService("vibrator", vibrator);

根据vibrator = new VibratorService(context);

            Slog.i(TAG, "led Service");
            ServiceManager.addService("led", new LedService());

3.4写com_android_LedService.cpp 称为JNI文件

(frameworks/base/services/core/jni/com_android_server_LedService.cpp)
注册本地方法,提供给LedService.java调用本地方法。

参考com_ android_VibratorService.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 <stdio.h>

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>


namespace android
{

static jint fd;

jint ledOpen(JNIEnv *env, jobject cls)
{
	fd = open("/dev/leds", O_RDWR);
	ALOGI("native ledOpen : %d", fd);
	if (fd >= 0)
		return 0;
	else
		return -1;
}

void ledClose(JNIEnv *env, jobject cls)
{
	ALOGI("native ledClose ...");
	close(fd);
}


jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
{
	int ret = ioctl(fd, status, which);
	ALOGI("native ledCtrl : %d, %d, %d", which, status, ret);
	return ret;
}


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

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

修改onload.cpp
(frameworks/base/services/core/jni/onload.cpp)
添加声明
int register_android_server_LedService(JNIEnv *env)
  register_android_server_VibratorService(env);
  register_android_server_LedService(env);

$ mmm frameworks/base/services(包含了JNI的内容)

$ android-5.0.2/ 下make snod//生成映像文件system.image

$ ./gen-img.sh 同步system.image

3.5修改编写总结

(1) AIDL

1. 把 ILedService.aidl 放入frameworks/base/core/java/android/os

2. 修改 frameworks/base/Android.mk  添加一行

        core/java/android/os/IVibratorService.aidl \

+       core/java/android/os/ILedService.aidl \

 

3. mmm frameworks/base

 

4. 它会生成:

 ./out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/ILedService.java

 

(2) Server : LedService.java

             SystemServer.java

把新文件上传到服务器, 所在目录:

frameworks/base/services/java/com/android/server/SystemServer.java

frameworks/base/services/core/java/com/android/server/LedService.java

不需要修改frameworks/base/services/core/Android.mk

它的内容里已经把该目录下所有JAVA文件自动包含进去了:

LOCAL_SRC_FILES += \

   $(call all-java-files-under,java)

(3) JNI :com_android_server_LedService.cpp

         onload.cpp

把新文件上传到服务器, 所在目录:

frameworks/base/services/core/jni/onload.cpp

frameworks/base/services/core/jni/com_android_server_LedService.cpp


修改frameworks/base/services/core/jni/Android.mk :

 $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \

+ $(LOCAL_REL_DIR)/com_android_server_LedService.cpp\

编译:

$ mmm frameworks/base/services

$ make snod

$ ./gen-img.sh

3.6下载system.image测试

所涉及代码的下载地址:

http://download.csdn.net/detail/fengyuwuzu0519/9756313

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值