s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(二 硬件抽象层HAL)
歡迎轉載,務必注明出處: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 #endifAndroid.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文件,添加如下:
然后編譯之,命令為:
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)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: s5p4418 Android 4.4.
- 下一篇: android--系统jar包引用