欢迎转载,务必注明出处:http://blog.csdn.net/wang_shuai_ww/article/details/44305599

本篇文章记录硬件抽象层。

还是跟之前一样,主要参考《Android系统源码情景分析》。

一.硬件抽象层

书里面写的是在/hardware/libhardware目录下写硬件抽象层,我这里并没有在该目录下,因为我使用的是与板子相关的,所以我就放在了板级目录下了,路径为/device/nexell/realarm,在/device/nexell/realarm路径下建立一个led文件夹来存放需要的.c、.h、.mk文件,我的文件名为led.c、led.h、Android.mk,源码分别如下:

led.c:

#include <hardware/hardware.h>
#include "led.h"#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>// 引入log头文件
#include <android/log.h>
// log标签
#define  TAG    "Led_Load_HAL"
// 定义info信息
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG,__VA_ARGS__)
// 定义debug信息
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
// 定义error信息
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)#define DEVICE_NAME     "/dev/real_led"
#define MODULE_NAME     "led"
#define MODULE_AUYHOR   "wsh_sean@qq.com"#define LED_ON      1
#define LED_OFF     0static int led_device_open(const struct hw_module_t *module, const char *id, struct hw_device_t **device);
static int led_device_close(struct hw_device_t *device);static int led_set_on(struct led_device_t *dev, int num);
static int led_set_off(struct led_device_t *dev, int num);static struct hw_module_methods_t led_module_methods = {open: led_device_open
};struct led_module_t HAL_MODULE_INFO_SYM = {common: {tag: HARDWARE_MODULE_TAG,version_major: 1,version_minor: 0,id: LED_HARDWARE_MODULE_ID,name: DEVICE_NAME,author: MODULE_AUYHOR,methods: &led_module_methods,}
};static int led_device_open(const struct hw_module_t *module, const char *id, struct hw_device_t **device) {if(!strcmp(id, LED_HARDWARE_DEVICE_ID)) {struct led_device_t *dev;dev = (struct led_device_t *)malloc(sizeof(struct led_device_t));if(!dev) {LOGE("Failed to alloc space for led_device_t");return -EFAULT;}memset(dev, 0, sizeof(struct led_device_t));dev->common.tag = HARDWARE_MODULE_TAG;dev->common.version = 0;dev->common.module = (hw_module_t *)module;dev->common.close = led_device_close;dev->set_on = led_set_on;dev->set_off = led_set_off;if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {LOGE("Failed to open device file "DEVICE_NAME"-- %s.", strerror(errno));free(dev);return -EFAULT;}*device = &(dev->common);LOGI("Open device file "DEVICE_NAME" successfully.");return 0;}return -EFAULT;
}static int led_device_close(struct hw_device_t *device){struct led_device_t *led_device = (struct led_device_t *)device;if(led_device){close(led_device->fd);free(led_device);}return 0;
}static int led_set_on(struct led_device_t *dev, int num){if(!dev){LOGE("Null dev pointer.");return -EFAULT;}LOGI("Set the first %d LED lights.", num);ioctl(dev->fd, LED_ON, num);return 0;
}static int led_set_off(struct led_device_t *dev, int num){if(!dev){LOGE("Null dev pointer.");return -EFAULT;}LOGI("Set the first %d LED close.", num);ioctl(dev->fd, LED_OFF, num);return 0;
}

led.h:

#ifndef ANDROID_LED_INTERFACE_H
#define ANDROID_LED_INTERFACE_H#include <hardware/hardware.h>__BEGIN_DECLS#define LED_HARDWARE_MODULE_ID  "led"
#define LED_HARDWARE_DEVICE_ID  "led"/*自定义模块结构体*/
struct led_module_t {struct hw_module_t common;
};/*自定义设备结构体*/
struct led_device_t {struct hw_device_t common;int fd;int (*set_on)(struct led_device_t *dev, int num);int (*set_off)(struct led_device_t *dev, int num);
};__END_DECLS
#endif

Android.mk:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := led.c
LOCAL_SHARED_LIBRARIES := liblog
#LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_MODULE := led.defaultinclude $(BUILD_SHARED_LIBRARY)

上面三个文件生成的是.so文件,该硬件抽象层为JNI方法提供接口。
编译命令是,进入Android源码根目录,执行下面的命令:

mmm ./device/nexell/realarm/led/

在执行上面的mmm命令时,先确保已经把Android源码的环境变量已经添加进系统,也就是是否执行过source ./build/envsetup.sh 这条命令了。

另外在使用mmm指令时,如果没有使用lunch命令选择过编译的板级目标,那么一般默认的可能不是需要的板级目标,所以要使用lunch命令进行选择一下,如下所示:

<strong><span style="color:#ff0000;">wsh@ubuntu:/wsh_space/nexell/s5p4418/debug/android/android$ lunchYou're building on LinuxLunch menu... pick a combo:1. aosp_arm-eng2. aosp_x86-eng3. aosp_mips-eng4. vbox_x86-eng5. mini_x86-userdebug6. mini_mips-userdebug7. mini_armv7a_neon-userdebug8. aosp_manta-userdebug9. aosp_drone2-userdebug10. aosp_drone-userdebug11. aosp_realarm-userdebug12. aosp_grouper-userdebug13. aosp_deb-userdebug14. aosp_flo-userdebug15. aosp_tilapia-userdebug16. aosp_hammerhead-userdebug17. aosp_mako-userdebugWhich would you like? [aosp_arm-eng]</span></strong>


我使用的是realarm的板子,所以选择数字11。

编译完成后,在out/target/product/realarm/system/lib/hw目录下即可看到led.default.so这个文件。

二.硬件访问服务JNI方法

下面的部分,新手可能比较难理解,不过没关系,照着写先实现功能再说,以后慢慢自然就了解了。

1.首先是硬件访问服务接口

硬件访问服务接口一般是在/frameworks/base/core/java/android/os目录下定义。我这里的文件名是ILedService.aidl,源码如下:

package android.os;interface ILedService{int seton(int num);int setoff(int num);
}

为了能够编译它需要修改 /frameworks/base/目录下的Android.mk文件,添加一行代码:core/java/android/os/ILedService.aidl \
是加在LOCAL_SRC_FILES += \后面的任何一个位置,一般是放在最后,由于太长,只贴一部分如下所示:

 packages/services/Proxy/com/android/net/IProxyCallback.aidl \packages/services/Proxy/com/android/net/IProxyPortListener.aidl \core/java/android/os/ILedService.aidl \

然后使用下面命令进行编译:

mmm ./frameworks/base/

2.实现硬件访问服务

/** Copyright (C) 2013 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.android.server;import android.content.Context;
import android.os.ILedService;
import android.util.Slog;/*** Shared singleton foreground thread for the system.  This is a thread for regular* foreground service operations, which shouldn't be blocked by anything running in* the background.  In particular, the shared background thread could be doing* relatively long-running operations like saving state to disk (in addition to* simply being a background priority), which can cause operations scheduled on it* to be delayed for a user-noticeable amount of time.*/
public class LedService extends ILedService.Stub {private static final String TAG = "LedService";private int mPtr = 0;LedService(){mPtr = init_native();if(mPtr == 0){Slog.e(TAG, "Failed to initialize Led service.");}}public int setOn(int num){if(mPtr == 0){Slog.e(TAG, "Led service is not initialize.");return 0;}setOn_native(mPtr, num);return 0;}public int setOff(int num){if(mPtr == 0){Slog.e(TAG, "Led service is not initialize.");return 0;}setOff_native(mPtr, num);return 0;}private static native int init_native();private static native int setOn_native(int ptr, int num);private static native int setOff_native(int ptr, int num);
};
<span style="font-family: Arial; background-color: rgb(255, 255, 255);">由上面代码可知,实现了硬件服务接口setOn和setOff的具体方法,由于java不能够直接使用HAL层提供的接口,所以这里使用native方式来与JNI方法连接。</span>
小知识,声明native标示的函数,在这里无需具体实现,它是java和c/c++连接的桥梁,具体的在JNI层实现这些函数。

编译:

mmm ./frameworks/base/services/java/

编译得到的server.jar就包含了LedService类。

3.硬件访问服务的JNI方法

目录为/frameworks/base/services/jni,文件命名为com_android_server_LedService.cpp,要注意命名格式,一般为com_android_server_xxx.cpp。

源码如下:

#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include "../../device/nexell/realarm/led/led.h"#include <stdio.h>// 引入log头文件
#include <android/log.h>
// log标签
#define LOG_TAG "LedServiceJNI"
// 定义info信息
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
// 定义debug信息
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
// 定义error信息
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)namespace android
{static jint led_seton(JNIEnv *env, jobject clazz, jint ptr, jint number){led_device_t *device = (led_device_t *)ptr;if(!device){LOGE("Device led is not open");return 0;}int num = number;LOGI("Set the first %d LED lights.", num);device->set_on(device, num);return num;}static jint led_setoff(JNIEnv *env, jobject clazz, jint ptr, jint number){led_device_t *device = (led_device_t *)ptr;if(!device){LOGE("Device led is not open");return 0;}int num = number;LOGI("Set the first %d LED close.", num);device->set_off(device, num);return num;}static inline int led_device_open(const hw_module_t *module, struct led_device_t **device){return module->methods->open(module, LED_HARDWARE_DEVICE_ID, (struct hw_device_t**)device);}static jint led_init(JNIEnv *env, jobject clazz){led_module_t *module;led_device_t *device;LOGI("Initializing HAL stub led......");if(hw_get_module(LED_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0){LOGI("Device led found");if(led_device_open(&(module->common), &device) == 0){LOGI("Device led is open.");return (jint)device;}LOGE("Failed to open device led.");return 0;}LOGE("Failed to get HAL stub led.");return 0;}static const JNINativeMethod method_table[] = {{"init_native", "()I", (void*)led_init},{"setOn_native", "(II)I", (void*)led_seton},{"setOff_native", "(II)I", (void*)led_setoff},};int register_android_server_LedService(JNIEnv *env){return jniRegisterNativeMethods(env, "com/android/server/LedService", method_table, NELEM(method_table));}
};

另外还需要修改两个文件。

修改/frameworks/base/services/jni/onload.cpp,完整文件如下:

/** Copyright (C) 2009 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#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_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_UsbDeviceManager(JNIEnv* env);
int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_SystemServer(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_AssetAtlasService(JNIEnv* env);
int register_android_server_LedService(JNIEnv *env);//user add
};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_LedService(env);//user addreturn JNI_VERSION_1_4;
}

添加了int register_android_server_LedService(JNIEnv *env);//user add和register_android_server_LedService(env);//user add。

修改/frameworks/base/services/jni/Android.mk文件,添加如下:

LOCAL_SRC_FILES:= \......com_android_server_LedService.cpp \onload.cpp

然后编译之,命令为:

mmm ./frameworks/base/services/jni/

生成的libandroid_servers.so文件就包含了我们实现的native方法了。 到此硬件访问服务LedService的实现就完成了,下面介绍怎么启动它。

三.启动硬件服务的方法

该部分的目的是让系统在启动的时候就加载led服务。

修改目录/frameworks/base/services/java/com/android/server/目录下的SystemServer.java文件,如下所示:

ActivityManagerService.self().systemReady(new Runnable() {public void run() {<pre name="code" class="cpp"><span style="white-space:pre">        </span>......
<span style="white-space:pre">      </span>//user addtry {Slog.i(TAG, "Realarmled service");ServiceManager.addService("led", new LedService());} catch (Throwable e) {Slog.e(TAG, "Failure starting Realarmled Service", e);}
<span style="white-space:pre">  </span>}

让系统在启动的时候加载LedService服务。

编译:

mmm ./frameworks/base/services/java/

到这里,out/target/product/realarm/system目录下就已经包含了我们所编译后的jar和.so文件了,打包系统文件烧写到开发板,下一个博客记录怎么写配套的应用程序app。

注意:打包之前检查一下ueventd.realarm.rc这个文件的最后时候有这一句/dev/real_led     0666   systemsystem,该句是修改驱动程序生成的real_led设备节点权限,以提供给HAL使用,否则会提示没有权限,无法打开的错误。

应用程序的写法介绍用两种方式,eclipse和Android源码目录下这两种方式。这里面涉及一些库的使用题,也是最头痛的事情,怎么让eclipse能够应用我们自己的类。

s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(二 硬件抽象层HAL)相关推荐

  1. s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(一 硬件驱动层)

    欢迎转载,务必注明出处:http://blog.csdn.net/wang_shuai_ww/article/details/44303069 本文章是记录Android开发中驱动层.HAL层.应用层 ...

  2. s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(三 APP应用)

    欢迎转载,务必注明出处:http://blog.csdn.net/wang_shuai_ww/article/details/44416041 eclipse完整工程下载地址:http://downl ...

  3. s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(二 硬件抽象层HAL 第二种 ioctl操作方法)

    欢迎转载,务必注明出处:http://blog.csdn.net/wang_shuai_ww/article/details/44407641 本篇与http://blog.csdn.net/wang ...

  4. Android 10.0 SystemUI下拉状态栏UI定制化开发系列(十二)

    目录 1.概述 2.核心代码 3.核心代码部分分析 3.1 NotificationStackScrollLayout.java代码分析 3.2接下来分析Activat

  5. Android应用开发 led 驱动层 hal硬件抽象层 应用层 详细教程记录(含源码)

    本篇文章是为了能够更好的搜索到介绍驱动到应用的详细介绍文章. 关于驱动层 hal硬件抽象层 应用层请参考s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录系列, ...

  6. 解密:IT运维艺术之集群(4层AND7层)

    负载均衡 概述; 负载均衡 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽.增加吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 负载均衡,英文名称为Load ...

  7. android调频收音机代码,android 收音机 FM 驱动 hal层 框架层以及应用层代码

    [实例简介] android 收音机 FM 驱动 hal层 框架层以及应用层代码 方法一 不需要framework部分 1.fm放到 \hardware\rk2x 2.FmRadio 放到 packa ...

  8. Android 底层驱动开发步骤——linux内核层、HAL层、JNI层

    1.Linux驱动实现 2.Linux内核驱动测试 3.Android HAL层实现 4.Aidl实现 5.Service java实现 6.Service jni 实现 7.注册service和jn ...

  9. Android 系统(4)---Android HAL层与Linux Kernel层驱动开发简介

    Android HAL层与Linux Kernel层驱动开发简介 近日稍微对Android中的驱动开发做了一些简要的了解,稍稍理清了一下Android驱动开发的套路,总结一下笔记. HAL:Hardw ...

最新文章

  1. 如何仿写thinkphp的C方法?
  2. 使用JavaMail发送邮件,465端口开启ssl加密传输
  3. mac下日期、时间戳互转
  4. Android: 生成安卓可使用的Tflite文件
  5. 关于用批处理写ftp上传文件
  6. 未为dll加载任何符号_专家发现aspersky 和Trend Micro安全性解决方案中的DLL劫持问题...
  7. python与数据处理_python数据处理:数据合并和Reshaping
  8. C++连接mysql及遇到的相关问题
  9. windows守护进程_在Linux的Windows子系统上(WSL)使用Docker(Ubuntu)
  10. pdf在线翻译_如何将英文的PDF文档翻译成中文简体?
  11. Excel条件格式化(conditional formatting)应用
  12. jQuery 学习笔记 事件委派
  13. R语言——决策树模型
  14. BAJ占领A股市场!
  15. 资深程序员的书单 - 转载自@Axb
  16. Atitit Atitit.软件兼容性原理----------API兼容 Qa7
  17. 蓝桥杯 省赛 杨辉三角形 python组(转)
  18. 微信分享只有链接没有图标和标题正文
  19. 利用 UPnP 的反射攻击分析
  20. 基于Vue使用Arco Design组件封装一个七牛云上传图片的函数

热门文章

  1. 网上选课系统java大作业_Java面向对象设计大作业——公选课选课系统
  2. mysql 两张表合并查询_mysql中的分区表和合并表详解(一个常见知识点)
  3. python应用于期货_Python期货量化交易基础教程(17)
  4. php 图片上传 水印,PHP - 图片上传并添加水印
  5. python定义x_Python 定义函数(示例代码)
  6. java压缩流的用法_Java对压缩包的操作(解压缩)
  7. 哪些计算机p玩游戏,有了这个神器,你的电脑玩什么游戏都带得动
  8. python requests发送websocket_Pywss - 用python实现WebSocket服务端
  9. android 模拟器 相册里传照片_引力相册APP下载-引力相册下载v1.1 官方版
  10. Pandas数据排序,人人都能学会的几种方法