s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(二 硬件抽象层HAL)
歡迎轉(zhuǎn)載,務(wù)必注明出處:http://blog.csdn.net/wang_shuai_ww/article/details/44305599
本篇文章記錄硬件抽象層。
還是跟之前一樣,主要參考《Android系統(tǒng)源碼情景分析》。
一.硬件抽象層
書(shū)里面寫(xiě)的是在/hardware/libhardware目錄下寫(xiě)硬件抽象層,我這里并沒(méi)有在該目錄下,因?yàn)槲沂褂玫氖桥c板子相關(guān)的,所以我就放在了板級(jí)目錄下了,路徑為/device/nexell/realarm,在/device/nexell/realarm路徑下建立一個(gè)led文件夾來(lái)存放需要的.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標(biāo)簽 #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"/*自定義模塊結(jié)構(gòu)體*/ struct led_module_t {struct hw_module_t common; };/*自定義設(shè)備結(jié)構(gòu)體*/ 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)上面三個(gè)文件生成的是.so文件,該硬件抽象層為JNI方法提供接口。
編譯命令是,進(jìn)入Android源碼根目錄,執(zhí)行下面的命令:
mmm ./device/nexell/realarm/led/ 在執(zhí)行上面的mmm命令時(shí),先確保已經(jīng)把Android源碼的環(huán)境變量已經(jīng)添加進(jìn)系統(tǒng),也就是是否執(zhí)行過(guò)source ./build/envsetup.sh 這條命令了。
另外在使用mmm指令時(shí),如果沒(méi)有使用lunch命令選擇過(guò)編譯的板級(jí)目標(biāo),那么一般默認(rèn)的可能不是需要的板級(jí)目標(biāo),所以要使用lunch命令進(jìn)行選擇一下,如下所示:
<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的板子,所以選擇數(shù)字11。
編譯完成后,在out/target/product/realarm/system/lib/hw目錄下即可看到led.default.so這個(gè)文件。
二.硬件訪問(wèn)服務(wù)JNI方法
下面的部分,新手可能比較難理解,不過(guò)沒(méi)關(guān)系,照著寫(xiě)先實(shí)現(xiàn)功能再說(shuō),以后慢慢自然就了解了。1.首先是硬件訪問(wèn)服務(wù)接口
硬件訪問(wèn)服務(wù)接口一般是在/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 += \后面的任何一個(gè)位置,一般是放在最后,由于太長(zhǎng),只貼一部分如下所示:
packages/services/Proxy/com/android/net/IProxyCallback.aidl \packages/services/Proxy/com/android/net/IProxyPortListener.aidl \core/java/android/os/ILedService.aidl \然后使用下面命令進(jìn)行編譯:
mmm ./frameworks/base/
2.實(shí)現(xiàn)硬件訪問(wèn)服務(wù)
/** 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);">由上面代碼可知,實(shí)現(xiàn)了硬件服務(wù)接口setOn和setOff的具體方法,由于java不能夠直接使用HAL層提供的接口,所以這里使用native方式來(lái)與JNI方法連接。</span> 小知識(shí),聲明native標(biāo)示的函數(shù),在這里無(wú)需具體實(shí)現(xiàn),它是java和c/c++連接的橋梁,具體的在JNI層實(shí)現(xiàn)這些函數(shù)。 編譯: mmm ./frameworks/base/services/java/編譯得到的server.jar就包含了LedService類(lèi)。
3.硬件訪問(wèn)服務(wù)的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標(biāo)簽 #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));} };
另外還需要修改兩個(gè)文件。
修改/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文件就包含了我們實(shí)現(xiàn)的native方法了。 到此硬件訪問(wèn)服務(wù)LedService的實(shí)現(xiàn)就完成了,下面介紹怎么啟動(dòng)它。
三.啟動(dòng)硬件服務(wù)的方法
該部分的目的是讓系統(tǒng)在啟動(dòng)的時(shí)候就加載led服務(wù)。
修改目錄/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>} 讓系統(tǒng)在啟動(dòng)的時(shí)候加載LedService服務(wù)。
編譯:
mmm ./frameworks/base/services/java/
到這里,out/target/product/realarm/system目錄下就已經(jīng)包含了我們所編譯后的jar和.so文件了,打包系統(tǒng)文件燒寫(xiě)到開(kāi)發(fā)板,下一個(gè)博客記錄怎么寫(xiě)配套的應(yīng)用程序app。
注意:打包之前檢查一下ueventd.realarm.rc這個(gè)文件的最后時(shí)候有這一句/dev/real_led? ? ?0666 ? systemsystem,該句是修改驅(qū)動(dòng)程序生成的real_led設(shè)備節(jié)點(diǎn)權(quán)限,以提供給HAL使用,否則會(huì)提示沒(méi)有權(quán)限,無(wú)法打開(kāi)的錯(cuò)誤。
應(yīng)用程序的寫(xiě)法介紹用兩種方式,eclipse和Android源碼目錄下這兩種方式。這里面涉及一些庫(kù)的使用題,也是最頭痛的事情,怎么讓eclipse能夠應(yīng)用我們自己的類(lèi)。
總結(jié)
以上是生活随笔為你收集整理的s5p4418 Android 4.4.2 驱动层 HAL层 服务层 应用层 开发流程记录(二 硬件抽象层HAL)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: s5p4418 Android 4.4.
- 下一篇: android sina oauth2.