- 浏览: 161696 次
- 性别:
- 来自: 马赛大回旋
文章分类
最新评论
-
ihopethatwell:
楼主请教一下,如果我添加packages/MSystemUI/ ...
Framework添加AIDL文件 -
285985787:
太感谢了 哈哈
eclipse查看android源码工程(附件) -
bluishoul:
应该比较大吧 还是自己编译吧 但是我的ubuntu是装的wub ...
Android 4.0 编译全程... -
地球小野花:
gzfreeman 写道请问用了多长时间?几个小时。具体没计算 ...
Android 4.0 编译全程... -
地球小野花:
bluishoul 写道求镜像 呵呵 bluishoul@gm ...
Android 4.0 编译全程...
文章导读:HAL硬件抽象层的实现及架构、Android API 与硬件平台的衔接、NDK的一些看法。
简介:Hardware Abstraction Layer 硬件抽象层是一个轻量级(lightweight)的的运行环境,提供了简单的设备驱动程序接口,应用程序使用设备驱动程序与底层硬件之间进行通信。HAL应用程序接口和ANSIC标准库结合在一起,这样用户可以使用C语言库函数来访问Android文件系统。下图是其直观的概念:
从图中,我们可以看到HAL是基于Linux Kernel与Libraries和Android Runtime之间。也就是说,HAL是底层硬件设备驱动程序暴露给Application Framework (也就是通常我们使用的Android API )的一个接口层。(可以浏览http://hi.baidu.com/aokikyon/blog/item/a66e0f87d8f55326c75cc32b.html HAL分析报告获得更详细的认识)
在网上也看到一些朋友写了重力感应器的api使用,那么以重力感应器Sensor为例子,看看重力感应器如何和Applications、Application Framework衔接。
1、下面Sensors.h的定义重力感应器对驱动程序部分的操作:
在源码./platform/hardware/Libardware /Include/Sensors.h目录下
#include <...>
__BEGIN_DECLS /** * The id of this module */ #define SENSORS_HARDWARE_MODULE_ID "sensors" /** * Name of the sensors device to open */ #define SENSORS_HARDWARE_CONTROL "control" #define SENSORS_HARDWARE_DATA "data" ..... /** convenience API for opening and closing a device */ static inline int sensors_control_open(const struct hw_module_t* module, struct sensors_control_device_t** device) { return module->methods->open(module, SENSORS_HARDWARE_CONTROL, (struct hw_device_t**)device); } static inline int sensors_control_close(struct sensors_control_device_t* device) { return device->common.close(&device->common); } static inline int sensors_data_open(const struct hw_module_t* module, struct sensors_data_device_t** device) { return module->methods->open(module, SENSORS_HARDWARE_DATA, (struct hw_device_t**)device); } static inline int sensors_data_close(struct sensors_data_device_t* device) { return device->common.close(&device->common); } __END_DECLS #endif // ANDROID_SENSORS_INTERFACE_H
2、JNI部分代码
加载该驱动的访问程序./framework/Jni/onLoad.cpp
#include "jni.h" #include "utils/Log.h" #include "utils/misc.h" #include "JNIHelp.h" namespace android { ... int register_android_server_SensorService(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) { LOGE("GetEnv failed!"); return result; } LOG_ASSERT(env, "Could not retrieve the env!"); //注册SensorService register_android_server_SensorService(env); return JNI_VERSION_1_4; }
向Application Framework提供接口部分./framework/Jni/com_android_server_SensorService.cpp
#define LOG_TAG "SensorService" #define LOG_NDEBUG 0 #include "utils/Log.h" //加载sensor.h文件 #include <hardware/sensors.h> #include "jni.h" #include "JNIHelp.h" namespace android { static struct file_descriptor_offsets_t { jclass mClass; jmethodID mConstructor; jfieldID mDescriptor; } gFileDescriptorOffsets; static struct parcel_file_descriptor_offsets_t { jclass mClass; jmethodID mConstructor; } gParcelFileDescriptorOffsets; static struct bundle_descriptor_offsets_t { jclass mClass; jmethodID mConstructor; jmethodID mPutIntArray; jmethodID mPutParcelableArray; } gBundleOffsets; /* * The method below are not thread-safe and not intended to be */ static sensors_control_device_t* sSensorDevice = 0; static jint android_init(JNIEnv *env, jclass clazz) { sensors_module_t* module; if (hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) { if (sensors_control_open(&module->common, &sSensorDevice) == 0) { const struct sensor_t* list; int count = module->get_sensors_list(module, &list); return count; } } return 0; } static jobject android_open(JNIEnv *env, jclass clazz) { native_handle_t* handle = sSensorDevice->open_data_source(sSensorDevice); if (!handle) { return NULL; } // new Bundle() jobject bundle = env->NewObject( gBundleOffsets.mClass, gBundleOffsets.mConstructor); if (handle->numFds > 0) { jobjectArray fdArray = env->NewObjectArray(handle->numFds, gParcelFileDescriptorOffsets.mClass, NULL); for (int i = 0; i < handle->numFds; i++) { // new FileDescriptor() jobject fd = env->NewObject(gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor); env->SetIntField(fd, gFileDescriptorOffsets.mDescriptor, handle->data[i]); // new ParcelFileDescriptor() jobject pfd = env->NewObject(gParcelFileDescriptorOffsets.mClass, gParcelFileDescriptorOffsets.mConstructor, fd); env->SetObjectArrayElement(fdArray, i, pfd); } // bundle.putParcelableArray("fds", fdArray); env->CallVoidMethod(bundle, gBundleOffsets.mPutParcelableArray, env->NewStringUTF("fds"), fdArray); } if (handle->numInts > 0) { jintArray intArray = env->NewIntArray(handle->numInts); env->SetIntArrayRegion(intArray, 0, handle->numInts, &handle->data[handle->numInts]); // bundle.putIntArray("ints", intArray); env->CallVoidMethod(bundle, gBundleOffsets.mPutIntArray, env->NewStringUTF("ints"), intArray); } // delete the file handle, but don't close any file descriptors native_handle_delete(handle); return bundle; } static jint android_close(JNIEnv *env, jclass clazz) { if (sSensorDevice->close_data_source) return sSensorDevice->close_data_source(sSensorDevice); else return 0; } static jboolean android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate) { int active = sSensorDevice->activate(sSensorDevice, sensor, activate); return (active<0) ? false : true; } static jint android_set_delay(JNIEnv *env, jclass clazz, jint ms) { return sSensorDevice->set_delay(sSensorDevice, ms); } static jint android_data_wake(JNIEnv *env, jclass clazz) { int res = sSensorDevice->wake(sSensorDevice); return res; } //提供给顶层实现的访问函数 static JNINativeMethod gMethods[] = { {"_sensors_control_init", "()I", (void*) android_init }, {"_sensors_control_open", "()Landroid/os/Bundle;", (void*) android_open }, {"_sensors_control_close", "()I", (void*) android_close }, {"_sensors_control_activate", "(IZ)Z", (void*) android_activate }, {"_sensors_control_wake", "()I", (void*) android_data_wake }, {"_sensors_control_set_delay","(I)I", (void*) android_set_delay }, }; int register_android_server_SensorService(JNIEnv *env) { jclass clazz; clazz = env->FindClass("java/io/FileDescriptor"); gFileDescriptorOffsets.mClass = (jclass)env->NewGlobalRef(clazz); gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V"); gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I"); clazz = env->FindClass("android/os/ParcelFileDescriptor"); gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V"); clazz = env->FindClass("android/os/Bundle"); gBundleOffsets.mClass = (jclass) env->NewGlobalRef(clazz); gBundleOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V"); gBundleOffsets.mPutIntArray = env->GetMethodID(clazz, "putIntArray", "(Ljava/lang/String;[I)V"); gBundleOffsets.mPutParcelableArray = env->GetMethodID(clazz, "putParcelableArray", "(Ljava/lang/String;[Landroid/os/Parcelable;)V"); return jniRegisterNativeMethods(env, "com/android/server/SensorService", gMethods, NELEM(gMethods)); } }; // namespace android
到了这里文件系统中底层的部分算是完成了。对于下层类库而言,我们可以通过HAL的方式建立android Api 和硬件设备驱动连接的桥梁。针对不同的硬件平台需要用户自己编写这几个函数的实现方式并通过android kernel里的驱动(当然有部分驱动可能位于文件系统中)来控制硬件行为。对于上层而言,可以看做是给顶层Java实现Android API提供一个访问接口。由于该文件是编译成系统 的*.so库文件,这与NDK中的为系统加载一个*.so相似。
3、Application Framework层是如何监听Sensor的物理数据
到了这里,用NDK的编程经验,我们可以通过system.load("*.so")获得某个库的访问,并使用里面的函数,进行想要的操作。而Google为了方便用户操作,用Java语言提供一些便捷访问的Application Framework将底层的c/c++实现的驱动或者其他细节封装起来,也就是我们所说的API(\(^o^)/~个人理解)。
终于到了熟悉的Android API 层了。
对于重力感应器,Android在./framework/base/service/java/com/android/server/SensorsService.java
import android.content.Context; import android.hardware.ISensorService; import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; import android.os.IBinder; import android.util.Config; import android.util.Slog; import android.util.PrintWriterPrinter; import android.util.Printer; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import com.android.internal.app.IBatteryStats; import com.android.server.am.BatteryStatsService; /** * Class that manages the device's sensors. It register clients and activate * the needed sensors. The sensor events themselves are not broadcasted from * this service, instead, a file descriptor is provided to each client they * can read events from. */ class SensorService extends ISensorService.Stub { static final String TAG = SensorService.class.getSimpleName(); private static final boolean DEBUG = false; private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; private static final int SENSOR_DISABLE = -1; private int mCurrentDelay = 0; /** * Battery statistics to be updated when sensors are enabled and disabled. */ final IBatteryStats mBatteryStats = BatteryStatsService.getService(); private final class Listener implements IBinder.DeathRecipient { final IBinder mToken; final int mUid; int mSensors = 0; int mDelay = 0x7FFFFFFF; Listener(IBinder token, int uid) { mToken = token; mUid = uid; } void addSensor(int sensor, int delay) { mSensors |= (1<<sensor); if (delay < mDelay) mDelay = delay; } void removeSensor(int sensor) { mSensors &= ~(1<<sensor); } boolean hasSensor(int sensor) { return ((mSensors & (1<<sensor)) != 0); } public void binderDied() { if (localLOGV) Slog.d(TAG, "sensor listener died"); synchronized(mListeners) { mListeners.remove(this); mToken.unlinkToDeath(this, 0); // go through the lists of sensors used by the listener that // died and deactivate them. for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) { if (hasSensor(sensor)) { removeSensor(sensor); deactivateIfUnusedLocked(sensor); try { mBatteryStats.noteStopSensor(mUid, sensor); } catch (RemoteException e) { // oops. not a big deal. } } } if (mListeners.size() == 0) { _sensors_control_wake(); _sensors_control_close(); } else { // TODO: we should recalculate the delay, since removing // a listener may increase the overall rate. } mListeners.notify(); } } } @SuppressWarnings("unused") public SensorService(Context context) { if (localLOGV) Slog.d(TAG, "SensorService startup"); _sensors_control_init(); } public Bundle getDataChannel() throws RemoteException { // synchronize so we do not require sensor HAL to be thread-safe. synchronized(mListeners) { return _sensors_control_open(); } } public boolean enableSensor(IBinder binder, String name, int sensor, int enable) throws RemoteException { if (localLOGV) Slog.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable); if (binder == null) { Slog.e(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")"); return false; } if (enable < 0 && (enable != SENSOR_DISABLE)) { Slog.e(TAG, "invalid enable parameter (enable=" + enable + ", sensor=" + name + ", id=" + sensor + ")"); return false; } boolean res; int uid = Binder.getCallingUid(); synchronized(mListeners) { res = enableSensorInternalLocked(binder, uid, name, sensor, enable); if (res == true) { // Inform battery statistics service of status change long identity = Binder.clearCallingIdentity(); if (enable == SENSOR_DISABLE) { mBatteryStats.noteStopSensor(uid, sensor); } else { mBatteryStats.noteStartSensor(uid, sensor); } Binder.restoreCallingIdentity(identity); } } return res; } private boolean enableSensorInternalLocked(IBinder binder, int uid, String name, int sensor, int enable) throws RemoteException { // check if we have this listener Listener l = null; for (Listener listener : mListeners) { if (binder == listener.mToken) { l = listener; break; } } if (enable != SENSOR_DISABLE) { // Activate the requested sensor if (_sensors_control_activate(sensor, true) == false) { Slog.w(TAG, "could not enable sensor " + sensor); return false; } if (l == null) { /* * we don't have a listener for this binder yet, so * create a new one and add it to the list. */ l = new Listener(binder, uid); binder.linkToDeath(l, 0); mListeners.add(l); mListeners.notify(); } // take note that this sensor is now used by this client l.addSensor(sensor, enable); } else { if (l == null) { /* * This client isn't in the list, this usually happens * when enabling the sensor failed, but the client * didn't handle the error and later tries to shut that * sensor off. */ Slog.w(TAG, "listener with binder " + binder + ", doesn't exist (sensor=" + name + ", id=" + sensor + ")"); return false; } // remove this sensor from this client l.removeSensor(sensor); // see if we need to deactivate this sensors= deactivateIfUnusedLocked(sensor); // if the listener doesn't have any more sensors active // we can get rid of it if (l.mSensors == 0) { // we won't need this death notification anymore binder.unlinkToDeath(l, 0); // remove the listener from the list mListeners.remove(l); // and if the list is empty, turn off the whole sensor h/w if (mListeners.size() == 0) { _sensors_control_wake(); _sensors_control_close(); } mListeners.notify(); } } // calculate and set the new delay int minDelay = 0x7FFFFFFF; for (Listener listener : mListeners) { if (listener.mDelay < minDelay) minDelay = listener.mDelay; } if (minDelay != 0x7FFFFFFF) { mCurrentDelay = minDelay; _sensors_control_set_delay(minDelay); } return true; } private void deactivateIfUnusedLocked(int sensor) { int size = mListeners.size(); for (int i=0 ; i<size ; i++) { if (mListeners.get(i).hasSensor(sensor)) { // this sensor is still in use, don't turn it off return; } } if (_sensors_control_activate(sensor, false) == false) { Slog.w(TAG, "could not disable sensor " + sensor); } } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { synchronized (mListeners) { Printer pr = new PrintWriterPrinter(pw); int c = 0; pr.println(mListeners.size() + " listener(s), delay=" + mCurrentDelay + " ms"); for (Listener l : mListeners) { pr.println("listener[" + c + "] " + "sensors=0x" + Integer.toString(l.mSensors, 16) + ", uid=" + l.mUid + ", delay=" + l.mDelay + " ms"); c++; } } } private ArrayList<Listener> mListeners = new ArrayList<Listener>(); //JNI提供的访问函数,将Application Framework和驱动衔接起来。 private static native int _sensors_control_init(); private static native Bundle _sensors_control_open(); private static native int _sensors_control_close(); private static native boolean _sensors_control_activate(int sensor, boolean activate); private static native int _sensors_control_set_delay(int ms); private static native int _sensors_control_wake(); }
接下来就是Core提供给我们使用的API了,这部分不在详解。
总结一下:对于NDK也不在啰唆,它和HAL一样,一个是提供商业保密程序,一个是google应厂商要求不希望公开源码。对于HAL的分析,我们也可以看到它大致的开发流程,也隐隐约约看到NDK的影子。若NDK涉及到硬件平台,它又该如何考虑夸平台呢?
发表评论
-
1123456
2012-02-08 11:41 851 -
Android 4.0 编译全程...
2011-11-18 13:35 9642进过几天的等待,几经波折终于把android 4.0 的代码下 ... -
Android 4.0 亮点之WI-FI Direct
2011-11-15 20:01 8750Wi-Fi Direct 来自官网: Android ... -
Android 4.0 源码下载中....
2011-11-15 11:02 8470经过3.0+ 版本不开源,终于等到4.0的开源,也可以看看4. ... -
Android RIL CDMA分支总结(1)
2011-05-16 21:36 4781Android RIL CDMA分支总结 1. CDM ... -
Android APN的设置问题
2011-03-18 13:08 2317Android APN的设置问题 原创作品,允许转 ... -
Android应用程序获得root权限
2011-03-16 11:17 3902Android应用程序获得root权限 原文:(htt ... -
eclipse查看android源码工程(附件)
2011-03-11 13:47 3883eclipse查看android源码工程(附件) 网上 ... -
快速体验Android 2.3
2010-12-07 10:21 1566由于Google目前只是开放了Android 2.3的源 ... -
Google 正式发布Android 2.3 -姜饼来了
2010-12-07 09:58 934最值得期待的视频通话功能。动起来吧~ -
Android Launcher解读之一AndroidManifest.xml
2010-11-29 16:50 0AndroidManifest.xml是何物?它在And ... -
android linux 基础知识总结
2010-09-06 11:03 0android linux 基础知识总结 (很好,很强大 ... -
Android源码下“系统级开发”——Settings例子
2010-09-04 13:50 9353在Android开发过程中,通常会遇到有很多隐藏的 ... -
PC机上体验Android x86操作系统
2010-09-03 13:15 7777Android X86是一款支持x86硬件平台上 ... -
Android应用程式编译成系统程序
2010-08-05 22:22 6989Android应用程式编译成系统程序简介 简 ... -
android.编译程序的模板.android.mk.txt
2010-08-03 00:31 1540# 编译动态库的模板: #Test S ... -
android.源码启动模拟器
2010-08-02 13:47 6373Android.源码中启动模 ... -
Android源码 Bluetooth设置的类说明
2010-08-01 23:57 6078Android应用程序(Setting)中有关蓝牙设定部 ... -
在Linux下Android编译中修改Java的环境
2010-07-31 16:44 2677Android 在编译过程中需要用到Java Versi ...
相关推荐
Android GPS HAL driver porting 笔记,详细的描述了Android GPS 硬件抽象层的基本架构
Android硬件抽象层从开发到使用有一个清晰的层次。这个层次恰好对应了Android系统的架构层次,它向下涉及到Linux内核,向上涉及到应用程序框架层的服务,以及应用程序层对它的使用。Android硬件抽象层模块的开发本身...
理解和使用Linux的硬件抽象层HAL 理解和使用Linux的硬件抽象层HAL
Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序
Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序
硬件抽象层( HAL), 应用库( CUL) zigbee的相关库的建立概念
Android硬件抽象层(HAL)模块编写JNI方法
范围 embedded-hal作为构建平台无关驱动程序生态系统的基础。(驱动程序意味着库 crates,它...不过,可以提议将通用功能的抽象包含在本指南embedded-hal中的描述中。 更多详情、使用方法,请下载后阅读README.md文件
系统软件模块与硬件之间的接口是嵌入式实时系统的主要特征,是系统设计过程中的必需环节,也是影响嵌入式系统应用前景的关键问题之一。硬件抽象层(Hardware Abstraction Layer,HAL)的引入可有效解决这一问题。
STM32Cube is an STMicroelectronics original initiative to significantly improve developer productivity by reducing development effort, time and cost. STM32Cube covers the STM32 portfolio
NXP LPC800系列微控制器的硬件抽象层 (HAL) ,用Rust编程语言编写。目前支持LPC82x和LPC845。LPC8xx HAL 为 LPC800 MCU 的特性提供了高级接口,安全、方便、高效。 LPC8xx HAL 利用 Rust 的类型系统来防止常见错误...
这篇总结是通过学习android源码情景分析得来的,是学习第二章HAL层的心得笔记,我学的比较浅,自己总结的知识,从硬件驱动到硬件抽象层到硬件服务到应用等的介绍
stm32l0xx-hal是 STMicro STM32L0xx 系列微控制器的硬件抽象层 (HAL)。 这个 crate 依赖 Adam Greig 的stm32l0 crate 来提供适当的寄存器定义并实现部分嵌入的 hal特征集。 基于Vitaly Domnikov 的stm32l1xx-hal...
STM Android 传感器硬件抽象层 ( HAL ) 为 STM 传感器定义了一个标准接口,允许 Android 不知道较低级别的驱动程序实现。HAL 库被打包成模块 (.so) 文件并由 Android 系统在适当的时候加载。有关详细信息,请参阅...
API参考方法:嵌入式hal用于嵌入式系统的硬件抽象层(HAL)该项目由HAL团队开发和维护。 API参考操作方法:添加新特征这是向Embedded-hal研究/讨论中添加新特征的建议方法。理想情况下,在提出新特征或一组特征之前...
基于硬件抽象层HAL的NiosⅡ嵌入式处理器系统设备管理模式研究.pdf
STM32Cube is an STMicroelectronics original initiative to significantly improve developer productivity by reducing development effort, time and cost. STM32Cube covers the STM32 portfolio.
常用的HAL API函数,集中整理了硬件抽象语言,便于查找
在Ubuntu Android简单介绍硬件抽象层(HAL)一文中,我们简要介绍了在Android系统为为硬件编写驱动程序的方法。简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中。接着Ubuntu ...