在Android 2.3(Gingerbread) 系统的时候,我写过一篇关于“Android 震动马达系统“的文章,当时的Linux内核还是2.6版本的。写那篇文章的目的,是想彻底的了解从硬件到驱动,再到应用的运作流程。完成了之后,文章一直仍在草稿箱里面没发表;今天看到,决定整理一下,重新发表。目的是想和大家分享自己对Android系统的一点认识:以马达为代表,来考究“Android是如何一步步工作的。它从硬件设计,到Linux驱动,再到HAL,再到JNI,再到Framework,最后到被应用调用,这整套的流程到底是怎么样的!” 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3404808.html Part 1 马达的硬件设计马达的震动原理很简单,给马达通电,马达就能震动。至于马达是如何工作,如何将电能转化为机械能,这不是我们关心的重点。但是,我们要需要了解如何控制马达的通电。在硬件上,我们是通过一个IO口(GPIO)去控制;对于马达而言,我们可以将IO理解为一个开关。当开关合上时,马达震动;开关断开,马达停止震动。 GPIO(General Purpose Input Output),称为通用输入/输出。它可以被配置为中断、输入、输出等类型,从而对各个IO进行控制。对于马达而已,GPIO就相当于一个开关。下面看看硬件原理图中的马达部分,如下图: 注:上面原理图对应CPU是“三星A8”。不同平台的马达,马达的接法和GPIO都不一样;但原理都是类似的。 原理图中红线标注部分的含义:GPH3_3是马达的GPIO。三星A8中有很多组GPIO,而马达对应和GPH3_3连接。
Part 2 马达的驱动代码知道马达的硬件设计之后,我们就可以进行Linux Driver开发工作,也就是编写马达的驱动。Linux的一个非常重要的特点,一切都是文件!而我们进行Linux Driver开发的目的,就是将硬件设备映射成一个文件;然后,我们可以通过操作文件,来操作对应的硬件设备。 OK!理解了驱动的作用和原理之后,我们接下来开发讲解马达的驱动开发。
1. Datasheet中相关信息 我们知道,马达是通过GPIO去控制;接下来,我们就是找到马达对应的GPIO信息,然后控制该GPIO即可。 通过马达的原理图,我们知道马达和GPH3_3相连接。我们查阅“三星A8 的Datasheet”,查找GPH3_3的相关信息。 所谓Datasheet,就是CPU芯片的数据手册。
上面记载了CPU的功能特性和操作方式等信息。任何一个厂家在发布它的芯片时,都会提供对应的Datasheet给它的客户;客户根据Datasheet上面所描述的CPU的特性,就可以进行相关的开发(当然,实际开发中可能还需要芯片厂商的支持)。例如,国内手机都是采用MTK平台,对于MTK方案开发商来说,它要开发MTK6577的产品。那么首先,MTK原厂会提供一份MTK6577的BSP包,BSP包中包括了MTK6577的Datasheet,也就是该芯片的数据手册。方案开发商有任何关于MTK6577的问题,都可以查阅该Datasheet。
三星A8的Datasheet中,关于GPH3_3的信息如下:
说明: (01) GPH3_3对应CPU中的寄存器是GPH3CON[3]。 (02) [15:12] 表示寄存器的第12~15位,一个寄存器共32 bits。而第三列的 0000, 0001, 0010, 0011, 1111表示“寄存器取不同值的时候,该GPIO的功能”。 例如, 0000表示将该GPIO作为输入,0001表示将GPIO作为输出,1111表示将该GPIO作为中断。 前面,我们已经说过,操作马达就是相当与将它作为一个开关操作。因此,我们需要将马达的GPIO设为“输入”类型;然后输入1,相当于开启马达;输入0,则是关闭马达!
下面,我们需要做的就是在Driver中将GPH3_3(也就是GPH3CON[3])映射为一个文件节点,并将它配置为“输入”类型,即将GPH3CON[3]的寄存器值设为0000。
2. 马达的驱动 我们编写马达驱动(drivers/misc/misc_sysfs.c),将马达(vibrator)注册道platform总线上。源码如下:
View Code
说明: 若您熟悉驱动开发,应该很容易理解上面的代码。不熟悉也不要紧,您只需要了解“Linux系统中,一切都是文件”,上面代码的作用是, 将马达(vibrator)映射到“/sys/devices/platform/misc_ctl/vibrator_onoff”文件上,我们可以通过读写vibrator_onoff来操作马达的开启和关闭。
有了马达的源码之后,我们还需要将该源码编译到Linux内核中。这就是通过Kconfig和Makefile来完成的,关于Kconfig和Makefile的知识,这里就不过多说明了。目前您只需要了解,通过Kconfig和Makefile,我们能将马达驱动编译到内核中,该驱动会在驱动加载的时候自动运行就可以了! 马达对应的Kconfig(driver/misc/Kconfig)内容如下: config MISC_VIBRATOR
tristate"misc vabrator"
default y
马达对应的Makefile(driver/misc/Makefile)内容如下: obj-$(CONFIG_MISC_VIBRATOR) += misc_sysfs.o
至此,我们已经完成马达的驱动开发了!也就是说,我们已经成功的将马达映射到文件节点上;接下来,我们通过操作文件节点,就可以操作马达了。下面从HAL层到Framework曾,都是基于Android4.2系统进行说明的。
Part 3 马达的HAL实现HAL (Hardware Abstraction Layer), 又称为“硬件抽象层”。在Linux驱动中,我们已经将马达设为映射为文件了;而该HAL层的存在的意义,就是“对设备文件进行操作,从而相当于硬件进行操作”。HAL层的作用,一是操作硬件设备,二是操作接口封装,外界能方便的使用HAL提供的接口直接操作硬件设备。 理解了HAL之后,我们看看Android中如何在HAL层对马达进行操作。 在Android系统中,我们在libhardware_legacy中,实现马达的HAL层控制。 vibrator.c的代码如下:
View Code
在kernel的驱动中,我们已经将马达注册到sys文件系统中(/sys/devices/platform/misc_ctl/vibrator_onoff)。在vibrator.c中,我们就是通过读写“vibrator_onoff文件节点”来实现对马达的操作。
Part 4 马达的JNI部分1 马达的JNI实现 JNI(Java Native Interface),中文是“Java本地接口”。 JNI是Java中一种技术,它存在的意义,是保证本地代码(C/C++代码)能在任何Java虚拟机下工作。简单点说,Java通过JNI接口,能够调用到C/C++代码。 关于“JNI的更多内容”,请参考“Android JNI和NDK学习系列文章”。 在了解了vibrator的HAL层实现之后,我们再来看看android是如何通过JNI将震动马达注册到android系统中。马达对应的JNI层代码路径如下:frameworks/base/services/jni/com_android_server_VibratorService.cpp com_android_server_VibratorService.cpp的源码如下:
View Code
下面,对这部分的JNI代码进行简单说明。 (01) 通过 jniRegisterNativeMethods(),我们将method_table中的方法注册到 com.android.server.VibratorService.java 中。配对表格如下: ---------------------------------------------------++++------------------------------------------- VibratorService.java com_android_server_VibratorService.cpp native static boolean vibratorExists(); static jboolean vibratorExists(JNIEnv *env, jobject clazz) native static void vibratorOn(long milliseconds); static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms) native static void vibratorOff(); static void vibratorOff(JNIEnv *env, jobject clazz) 通过JNI,我们就能将Java层和HAL层的代码联系起来。
在继续接下来的研究之前,我们先搞清楚:JNI如何和HAL层代码关联起来的。即com_android_server_VibratorService.cpp是如何调用到vibrator.c中的代码的。 (01) vibrator.c封装到libhardware_legacy.so中的步骤 在hardware/libhardware_legacy/vibrator/Android.mk中,会将vibrator.c添加到 LOCAL_SRC_FILES 变量中。 LOCAL_SRC_FILES += vibrator/vibrator.c 在hardware/libhardware_legacy/Android.mk中,它会调用子目录的Android.mk并将它们导入当前的Android.mk中。 legacy_modules := power uevent vibrator wifi qemu qemu_tracing SAVE_MAKEFILES := $(call all-named-subdir-makefiles,$(legacy_modules)) LEGACY_AUDIO_MAKEFILES := $(call all-named-subdir-makefiles,audio) include $(SAVE_MAKEFILES) ... LOCAL_MODULE:= libhardware_legacy include $(BUILD_SHARED_LIBRARY) 在“我们编译Android系统”或“通过 mmm hardware/libhardware_legacy进行模块编译”的时候,就会生成库libhardware_legacy.so;而且vibrator.c被包含在该库中。 (02) 在 com_android_server_VibratorService.cpp 对应的Android.mk中,会导入libhardware_legacy.so。 LOCAL_SRC_FILES:= com_android_server_VibratorService.cpp ...
LOCAL_SHARED_LIBRARIES := libhardware_legacy ...
LOCAL_MODULE:= libandroid_servers
include $(BUILD_SHARED_LIBRARY)
Part 5 马达的Framework层实现应用层操作马达,是通过马达服务进行操作的。而马达服务是通过aidl实现的,aidl是Android进程间的通信方式。关于aidl的更多说明可以参考“Android Service总结06 之AIDL”。 马达服务涉及的主要文件如下: 1 frameworks/base/services/java/com/android/server/SystemServer.java 2 frameworks/base/services/java/com/android/server/VibratorService.java 3 frameworks/base/core/java/android/os/IVibratorService.aidl 4 frameworks/base/core/java/android/os/Vibrator.java 5 frameworks/base/core/java/android/os/SystemVibrator.java 下面,对这几个文件的功能进行简要说明。 文件1: SystemServer.java 文件2: IVibratorService.aidl 文件3: VibratorService.java 文件4: Vibrator.java 文件5: SystemVibrator.java 下面,我们继续Read The Fucking Source Code,加深对上面知识的理解。 1 SystemServer.java 在frameworks/base/services/java/com/android/server/SystemServer.java中关于马达的代码如下: 1 { 2 VibratorService vibrator = null; 3 4 Slog.i(TAG, "Vibrator Service"); 5 vibrator = new VibratorService(context); 6 ServiceManager.addService("vibrator", vibrator); 7 8 ... 9 10 try { 11 vibrator.systemReady(); 12 } catch (Throwable e) { 13 reportWtf("making Vibrator Service ready", e); 14 } 15 } 从中,我们知道:
2 IVibratorService.aidl 在查看VibratorService.java之前,我们先看看它对应的aidl文件。frameworks/base/core/java/android/os/IVibratorService.aidl源码如下: 1 package android.os; 2 3 /** {@hide} */ 4 interface IVibratorService 5 { 6 boolean hasVibrator(); 7 void vibrate(long milliseconds, IBinder token); 8 void vibratePattern(in long[] pattern, int repeat, IBinder token); 9 void cancelVibrate(IBinder token); 10 }
3 VibratorService.java frameworks/base/services/java/com/android/server/VibratorService.java源码如下:
View Code
其中,VibratorService实际上是通过“本地方法”去控制马达的。例如,hasVibratora()最终是通过vibratorExists()来判断马达是否存在的。
4 Vibrator.java frameworks/base/core/java/android/os/Vibrator.java源码如下: 1 package android.os; 2 3 import android.content.Context; 4 5 public abstract class Vibrator { 6 7 public Vibrator() { 8 } 9 10 public abstract boolean hasVibrator(); 11 12 public abstract void vibrate(long milliseconds); 13 14 public abstract void vibrate(long[] pattern, int repeat); 15 16 public abstract void cancel(); 17 }
5 SystemVibrator.java frameworks/base/core/java/android/os/SystemVibrator.java源码如下:
View Code
说明:
在讲解“应用层如何通过getSystemService(VIBRATOR_SERVICE)获取马达服务,然后进一步的操作马达”之前,我们先看看应用层的马达操作示例!
Part 6 马达的应用示例1 权限 调用马达服务,需要在manifest中添加相应的权限: <!-- 震动马达权限 --> <uses-permission android:name="android.permission.VIBRATE"/> 2 源码 源码如下: 1 package com.test; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.os.Vibrator; 6 import android.view.View; 7 import android.view.View.OnClickListener; 8 import android.widget.Button; 9 import android.widget.ToggleButton; 10 import android.util.Log; 11 12 public class VibratorTest extends Activity { 13 private static final String TAG = "skywang-->VibratorTest"; 14 15 private Vibrator mVibrator; 16 private Button mOnce = null; 17 private ToggleButton mEndless = null; 18 19 @Override 20 protected void onCreate(Bundle savedInstanceState) { 21 super.onCreate(savedInstanceState); 22 setContentView(R.layout.main); 23 24 // 获取震动马达服务 25 mVibrator= (Vibrator) getSystemService(VIBRATOR_SERVICE); 26 27 mOnce = (Button) findViewById(R.id.vib_once); 28 mOnce.setOnClickListener(new View.OnClickListener() { 29 30 @Override 31 public void onClick(View view) { 32 //震动指定时间 33 mVibrator.vibrate(100); 34 } 35 }); 36 37 mEndless = (ToggleButton) findViewById(R.id.vib_endless); 38 mEndless.setOnClickListener(new OnClickListener() { 39 @Override 40 public void onClick(View v) { 41 if (mEndless.isChecked()) { 42 //等待100ms后,按数组所给数值间隔震动;其后为重复次数,-1为不重复,0一直震动 43 mVibrator.vibrate(new long[]{100,20,100,40,100,60}, 0); 44 } else { 45 // 取消震动 46 mVibrator.cancel(); 47 } 48 } 49 }); 50 51 } 52 53 @Override 54 protected void onStop() { 55 super.onStop(); 56 if (mVibrator != null) 57 mVibrator= null; 58 } 59 } 点击下载:Android马达应用代码
Part 7 马达的应用如何调用到马达服务的接下来,我们分析一下如何获取马达服务的:即 mVibrator= (Vibrator) getSystemService(VIBRATOR_SERVICE) 的工作原理。 1. Context.java中的getSystemService() getSystemService()定义在frameworks/base/core/java/android/content/Context.java中,源码如下: public abstract Object getSystemService(String name); Context.java中的getSystemService() 是个抽象方法,它的实现在ContextImpl.java中。
2. ContextImpl.java中的getSystemService() frameworks/base/core/java/android/app/ContextImpl.java中的 getSystemService() 源码如下: 1 @Override 2 public Object getSystemService(String name) { 3 ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); 4 return fetcher == null ? null : fetcher.getService(this); 5 }
3. ContextImpl.java中的SYSTEM_SERVICE_MAP SYSTEM_SERVICE_MAP是一个HashMap对象,它的相关代码如下: 1 private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = 2 new HashMap<String, ServiceFetcher>(); 3 4 SYSTEM_SERVICE_MAP的初始化,是在ContextImpl.java通过static静态模块完成的。源码如下: 5 static { 6 7 ... 8 9 // 注册“传感器服务” 10 registerService(SENSOR_SERVICE, new ServiceFetcher() { 11 public Object createService(ContextImpl ctx) { 12 return new SystemSensorManager(ctx.mMainThread.getHandler().getLooper()); 13 }}); 14 15 // 注册其它服务 ... 16 17 // 注册马达服务 18 registerService(VIBRATOR_SERVICE, new ServiceFetcher() { 19 public Object createService(ContextImpl ctx) { 20 return new SystemVibrator(); 21 }}); 22 23 ... 24 } 说明:在上面的static静态模块中,会通过registerService()注册一系列的服务,包括马达服务。注册服务是通过registerService()实现的,下面我们看看registerService()的定义。 1 private static int sNextPerContextServiceCacheIndex = 0; 2 private static void registerService(String serviceName, ServiceFetcher fetcher) { 3 if (!(fetcher instanceof StaticServiceFetcher)) { 4 fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++; 5 } 6 SYSTEM_SERVICE_MAP.put(serviceName, fetcher); 7 } 从中,我们知道,在registerService()中,会通过 SYSTEM_SERVICE_MAP.put(serviceName, fetcher) 将serviceName和fetcher添加到哈希表SYSTEM_SERVICE_MAP中。 OK,接着往下看。
3. ContextImpl.java中的fetcher.getService(this) 1 public Object getSystemService(String name) { 2 ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); 3 return fetcher == null ? null : fetcher.getService(this); 4 } 我们已经知道SYSTEM_SERVICE_MAP是哈希表,通过SYSTEM_SERVICE_MAP.get(name)返回的是ServiceFetcher对象。 1 static class ServiceFetcher { 2 int mContextCacheIndex = -1; 3 4 public Object getService(ContextImpl ctx) { 5 ArrayList<Object> cache = ctx.mServiceCache; 6 Object service; 7 synchronized (cache) { 8 if (cache.size() == 0) { 9 10 // “服务对象”缓冲 11 for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) { 12 cache.add(null); 13 } 14 } else { 15 service = cache.get(mContextCacheIndex); 16 if (service != null) { 17 return service; 18 } 19 } 20 service = createService(ctx); 21 cache.set(mContextCacheIndex, service); 22 return service; 23 } 24 } 25 26 public Object createService(ContextImpl ctx) { 27 throw new RuntimeException("Not implemented"); 28 } 29 } 从中,我们发现,getService()实际上返回的是“通过createService(ctx)创建的service对象”。 至此,我们知道:getSystemService(VIBRATOR_SERVICE) 返回的是 SystemVibrator对象!SystemVibrator前面已经分析过,这里就不再说明了。 |
|
来自: JUST SO LAZY > 《java\android》