原文
HAL (Hardware Abstraction Layer), 又称为“硬件抽象层”。在Linux驱动中,我们已经将马达设为映射为文件了;而该HAL层的存在的意义,就是 “对设备文件进行操作,从而相当于硬件进行操作 ”。HAL层的作用, 一是操作硬件设备 ,二是 操作接口封装,外界能方便的使用HAL提供的接口直接操作硬件设备。
理解了HAL之后,我们看看Android中如何在HAL层对马达进行操作。
在Android系统中,我们在libhardware_legacy中,实现马达的HAL层控制。
马达在HAL中的代码路径: hardware/libhardware_legacy/vibrator/vibrator.c
vibrator.c的代码如下:
![](http://img0.tuicool.com/7JJJry.gif)
1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include <hardware_legacy/vibrator.h> 17 #include "qemu.h" 18 19 #include <stdio.h> 20 #include <unistd.h> 21 #include <fcntl.h> 22 #include <errno.h> 23 24 #define THE_DEVICE "/sys/devices/platform/misc_ctl/vibrator_onoff" 25 26 int vibrator_exists() 27 { 28 int fd; 29 30 #ifdef QEMU_HARDWARE 31 if (qemu_check()) { 32 return 1; 33 } 34 #endif 35 36 fd = open(THE_DEVICE, O_RDWR); 37 if(fd < 0) 38 return 0; 39 close(fd); 40 return 1; 41 } 42 43 static int sendit(int timeout_ms) 44 { 45 int nwr, ret, fd; 46 char value[20]; 47 48 #ifdef QEMU_HARDWARE 49 if (qemu_check()) { 50 return qemu_control_command( "vibrator:%d", timeout_ms ); 51 } 52 #endif 53 54 fd = open(THE_DEVICE, O_RDWR); 55 if(fd < 0) 56 return errno; 57 58 nwr = sprintf(value, "%d\n", timeout_ms); 59 ret = write(fd, value, nwr); 60 61 close(fd); 62 63 return (ret == nwr) ? 0 : -1; 64 } 65 66 int vibrator_on(int timeout_ms) 67 { 68 /* constant on, up to maximum allowed time */ 69 return sendit(timeout_ms); 70 } 71 72 int vibrator_off() 73 { 74 return sendit(0); 75 }
在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的源码如下:
![](http://img0.tuicool.com/7JJJry.gif)
1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "VibratorService" 18 19 #include "jni.h" 20 #include "JNIHelp.h" 21 #include "android_runtime/AndroidRuntime.h" 22 23 #include <utils/misc.h> 24 #include <utils/Log.h> 25 #include <hardware_legacy/vibrator.h> 26 27 #include <stdio.h> 28 29 namespace android 30 { 31 32 static jboolean vibratorExists(JNIEnv *env, jobject clazz) 33 { 34 return vibrator_exists() > 0 ? JNI_TRUE : JNI_FALSE; 35 } 36 37 static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms) 38 { 39 // ALOGI("vibratorOn\n"); 40 vibrator_on(timeout_ms); 41 } 42 43 static void vibratorOff(JNIEnv *env, jobject clazz) 44 { 45 // ALOGI("vibratorOff\n"); 46 vibrator_off(); 47 } 48 49 static JNINativeMethod method_table[] = { 50 { "vibratorExists", "()Z", (void*)vibratorExists }, 51 { "vibratorOn", "(J)V", (void*)vibratorOn }, 52 { "vibratorOff", "()V", (void*)vibratorOff } 53 }; 54 55 int register_android_server_VibratorService(JNIEnv *env) 56 { 57 return jniRegisterNativeMethods(env, "com/android/server/VibratorService", 58 method_table, NELEM(method_table)); 59 } 60 61 };
下面,对这部分的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层的代码联系起来。
以vibratorOff()来说,我们在VibratorService.java中调用vibratorOff();实际上会调用到com_android_server_VibratorService.cpp中的vibratorOff()函数;进一步会调用到vibrator_off()函数,而vibrator_off()是我们在 “HAL层的vibrator.c中的接口”。
2 马达的JNI如何和HAL关联方式
在继续接下来的研究之前,我们先搞清楚: JNI如何和HAL层代码关联起来的。 即com_android_server_VibratorService.cpp是如何调用到vibrator.c中的代码的。
实际上道理很简单,我们先将vibrator.c封装成.so库;然后在com_android_server_VibratorService.cpp中导入该库,就可以调用vibrator.c的接口了。下面,看看Android中具体是如何做到的。
(01) vibrator.c封装到libhardware_legacy.so中的步骤
在hardware/libhardware_legacy/vibrator/Android.mk中,会将vibrator.c添加到 LOCAL_SRC_FILES 变量中。
hardware/libhardware_legacy/vibrator/Android.mk源码如下:
LOCAL_SRC_FILES += vibrator/vibrator.c
在hardware/libhardware_legacy/Android.mk中,它会调用子目录的Android.mk并将它们导入当前的Android.mk中。
hardware/libhardware_legacy/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。
com_android_server_VibratorService.cpp 对应的frameworks/base/services/jni/Android.mk 的源码如下:
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
它是系统服务,作用是 启动、管理系统服务 ,包括“马达服务、Wifi服务、Activity管理服务”等等。
SystemServer是通过Zygote启动的,而Zygote又是在init中启动的,init则是kernel加载完毕之后启动的第一个进程。在这里,我们只需要知道“SystemServer是用来 启动/管理马达服务 即可。”
文件2: IVibratorService.aidl
它是马达服务对应的aidl配置文件。我们在aidl中定义了其它进程可以访问的外部接口;然后再通过VibratorService.java实现这些接口。
文件3: VibratorService.java
它是马达服务对应的aidl接口的实现程序。它实现IVibratorService.aidl的接口,从而实现马达服务;它的函数接口,是通过调用JNI层对应的马达控制函数来实现的。
文件4: Vibrator.java
它是马达服务开放给应用层的调用类。理论上讲,我们完全可以通过aidl直接调用马达服务,而不需要Vibrator.java类。但是!既然它存在,就肯定有它的理由。事实的确如此,Google之所以这么做。有以下几个原因:
第一,提供统一而且方便的服务调用方式。 这里的 “统一” ,是指和所有其它的系统服务一样,我们调用服务时,需先通过getSystemService()获取服务,然后再调用服务的函数接口。这里的 “方便” ,是指若我们直接通过aidl调用,操作比较繁琐(若你用过aidl就会知道,需要先实现ServiceConnection接口以获取IBinder对象,然后再通过IBinder对象调用aidl的接口); 而Vibrator.java封装之后的接口,将许多细节都隐藏了,非常便于应用者调用!
第二,基于安全的考虑。 Vibrator.java封装隐藏了许多细节,而这些都是应用开发者不必要知道的。
第三,Vibrator是抽象类。 它便于我们支持不同类型的马达:包括“将马达直接映射到文件”以及“将马达注册到输入子系统”中。
文件5: SystemVibrator.java
它是Vibrator.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 }
从中,我们知道:
(01) SystemServer中会通过VibratorService()新建马达服务,并将其添加到ServiceManager中。
(02) 在Android系统启动完成之后,SystemServer会调用vibrator.systemReady()。
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源码如下:
![](http://img0.tuicool.com/7JJJry.gif)
1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.server;
18
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.pm.PackageManager;
24 import android.database.ContentObserver;
25 import android.hardware.input.InputManager;
26 import android.os.Handler;
27 import android.os.IVibratorService;
28 import android.os.PowerManager;
29 import android.os.Process;
30 import android.os.RemoteException;
31 import android.os.IBinder;
32 import android.os.Binder;
33 import android.os.SystemClock;
34 import android.os.UserHandle;
35 import android.os.Vibrator;
36 import android.os.WorkSource;
37 import android.provider.Settings;
38 import android.provider.Settings.SettingNotFoundException;
39 import android.util.Slog;
40 import android.view.InputDevice;
41
42 import java.util.ArrayList;
43 import java.util.LinkedList;
44 import java.util.ListIterator;
45
46 public class VibratorService extends IVibratorService.Stub
47 implements InputManager.InputDeviceListener {
48 private static final String TAG = "VibratorService";
49
50 private final LinkedList<Vibration> mVibrations;
51 private Vibration mCurrentVibration;
52 private final WorkSource mTmpWorkSource = new WorkSource();
53 private final Handler mH = new Handler();
54
55 private final Context mContext;
56 private final PowerManager.WakeLock mWakeLock;
57 private InputManager mIm;
58
59 volatile VibrateThread mThread;
60
61 // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
62 // to be acquired
63 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
64 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
65 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
66
67 native static boolean vibratorExists();
68 native static void vibratorOn(long milliseconds);
69 native static void vibratorOff();
70
71 private class Vibration implements IBinder.DeathRecipient {
72 private final IBinder mToken;
73 private final long mTimeout;
74 private final long mStartTime;
75 private final long[] mPattern;
76 private final int mRepeat;
77 private final int mUid;
78
79 Vibration(IBinder token, long millis, int uid) {
80 this(token, millis, null, 0, uid);
81 }
82
83 Vibration(IBinder token, long[] pattern, int repeat, int uid) {
84 this(token, 0, pattern, repeat, uid);
85 }
86
87 private Vibration(IBinder token, long millis, long[] pattern,
88 int repeat, int uid) {
89 mToken = token;
90 mTimeout = millis;
91 mStartTime = SystemClock.uptimeMillis();
92 mPattern = pattern;
93 mRepeat = repeat;
94 mUid = uid;
95 }
96
97 public void binderDied() {
98 synchronized (mVibrations) {
99 mVibrations.remove(this);
100 if (this == mCurrentVibration) {
101 doCancelVibrateLocked();
102 startNextVibrationLocked();
103 }
104 }
105 }
106
107 public boolean hasLongerTimeout(long millis) {
108 if (mTimeout == 0) {
109 // This is a pattern, return false to play the simple
110 // vibration.
111 return false;
112 }
113 if ((mStartTime + mTimeout)
114 < (SystemClock.uptimeMillis() + millis)) {
115 // If this vibration will end before the time passed in, let
116 // the new vibration play.
117 return false;
118 }
119 return true;
120 }
121 }
122
123 VibratorService(Context context) {
124 // Reset the hardware to a default state, in case this is a runtime
125 // restart instead of a fresh boot.
126 vibratorOff();
127
128 mContext = context;
129 PowerManager pm = (PowerManager)context.getSystemService(
130 Context.POWER_SERVICE);
131 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
132 mWakeLock.setReferenceCounted(true);
133
134 mVibrations = new LinkedList<Vibration>();
135
136 IntentFilter filter = new IntentFilter();
137 filter.addAction(Intent.ACTION_SCREEN_OFF);
138 context.registerReceiver(mIntentReceiver, filter);
139 }
140
141 public void systemReady() {
142 mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
143
144 mContext.getContentResolver().registerContentObserver(
145 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
146 new ContentObserver(mH) {
147 @Override
148 public void onChange(boolean selfChange) {
149 updateInputDeviceVibrators();
150 }
151 }, UserHandle.USER_ALL);
152
153 mContext.registerReceiver(new BroadcastReceiver() {
154 @Override
155 public void onReceive(Context context, Intent intent) {
156 updateInputDeviceVibrators();
157 }
158 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
159
160 updateInputDeviceVibrators();
161 }
162
163 public boolean hasVibrator() {
164 return doVibratorExists();
165 }
166
167 public void vibrate(long milliseconds, IBinder token) {
168 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
169 != PackageManager.PERMISSION_GRANTED) {
170 throw new SecurityException("Requires VIBRATE permission");
171 }
172 int uid = Binder.getCallingUid();
173 // We're running in the system server so we cannot crash. Check for a
174 // timeout of 0 or negative. This will ensure that a vibration has
175 // either a timeout of > 0 or a non-null pattern.
176 if (milliseconds <= 0 || (mCurrentVibration != null
177 && mCurrentVibration.hasLongerTimeout(milliseconds))) {
178 // Ignore this vibration since the current vibration will play for
179 // longer than milliseconds.
180 return;
181 }
182
183 Vibration vib = new Vibration(token, milliseconds, uid);
184 synchronized (mVibrations) {
185 removeVibrationLocked(token);
186 doCancelVibrateLocked();
187 mCurrentVibration = vib;
188 startVibrationLocked(vib);
189 }
190 }
191
192 private boolean isAll0(long[] pattern) {
193 int N = pattern.length;
194 for (int i = 0; i < N; i++) {
195 if (pattern[i] != 0) {
196 return false;
197 }
198 }
199 return true;
200 }
201
202 public void vibratePattern(long[] pattern, int repeat, IBinder token) {
203 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
204 != PackageManager.PERMISSION_GRANTED) {
205 throw new SecurityException("Requires VIBRATE permission");
206 }
207 int uid = Binder.getCallingUid();
208 // so wakelock calls will succeed
209 long identity = Binder.clearCallingIdentity();
210 try {
211 if (false) {
212 String s = "";
213 int N = pattern.length;
214 for (int i=0; i<N; i++) {
215 s += " " + pattern[i];
216 }
217 Slog.i(TAG, "vibrating with pattern: " + s);
218 }
219
220 // we're running in the server so we can't fail
221 if (pattern == null || pattern.length == 0
222 || isAll0(pattern)
223 || repeat >= pattern.length || token == null) {
224 return;
225 }
226
227 Vibration vib = new Vibration(token, pattern, repeat, uid);
228 try {
229 token.linkToDeath(vib, 0);
230 } catch (RemoteException e) {
231 return;
232 }
233
234 synchronized (mVibrations) {
235 removeVibrationLocked(token);
236 doCancelVibrateLocked();
237 if (repeat >= 0) {
238 mVibrations.addFirst(vib);
239 startNextVibrationLocked();
240 } else {
241 // A negative repeat means that this pattern is not meant
242 // to repeat. Treat it like a simple vibration.
243 mCurrentVibration = vib;
244 startVibrationLocked(vib);
245 }
246 }
247 }
248 finally {
249 Binder.restoreCallingIdentity(identity);
250 }
251 }
252
253 public void cancelVibrate(IBinder token) {
254 mContext.enforceCallingOrSelfPermission(
255 android.Manifest.permission.VIBRATE,
256 "cancelVibrate");
257
258 // so wakelock calls will succeed
259 long identity = Binder.clearCallingIdentity();
260 try {
261 synchronized (mVibrations) {
262 final Vibration vib = removeVibrationLocked(token);
263 if (vib == mCurrentVibration) {
264 doCancelVibrateLocked();
265 startNextVibrationLocked();
266 }
267 }
268 }
269 finally {
270 Binder.restoreCallingIdentity(identity);
271 }
272 }
273
274 private final Runnable mVibrationRunnable = new Runnable() {
275 public void run() {
276 synchronized (mVibrations) {
277 doCancelVibrateLocked();
278 startNextVibrationLocked();
279 }
280 }
281 };
282
283 // Lock held on mVibrations
284 private void doCancelVibrateLocked() {
285 if (mThread != null) {
286 synchronized (mThread) {
287 mThread.mDone = true;
288 mThread.notify();
289 }
290 mThread = null;
291 }
292 doVibratorOff();
293 mH.removeCallbacks(mVibrationRunnable);
294 }
295
296 // Lock held on mVibrations
297 private void startNextVibrationLocked() {
298 if (mVibrations.size() <= 0) {
299 mCurrentVibration = null;
300 return;
301 }
302 mCurrentVibration = mVibrations.getFirst();
303 startVibrationLocked(mCurrentVibration);
304 }
305
306 // Lock held on mVibrations
307 private void startVibrationLocked(final Vibration vib) {
308 if (vib.mTimeout != 0) {
309 doVibratorOn(vib.mTimeout);
310 mH.postDelayed(mVibrationRunnable, vib.mTimeout);
311 } else {
312 // mThread better be null here. doCancelVibrate should always be
313 // called before startNextVibrationLocked or startVibrationLocked.
314 mThread = new VibrateThread(vib);
315 mThread.start();
316 }
317 }
318
319 // Lock held on mVibrations
320 private Vibration removeVibrationLocked(IBinder token) {
321 ListIterator<Vibration> iter = mVibrations.listIterator(0);
322 while (iter.hasNext()) {
323 Vibration vib = iter.next();
324 if (vib.mToken == token) {
325 iter.remove();
326 unlinkVibration(vib);
327 return vib;
328 }
329 }
330 // We might be looking for a simple vibration which is only stored in
331 // mCurrentVibration.
332 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
333 unlinkVibration(mCurrentVibration);
334 return mCurrentVibration;
335 }
336 return null;
337 }
338
339 private void unlinkVibration(Vibration vib) {
340 if (vib.mPattern != null) {
341 // If Vibration object has a pattern,
342 // the Vibration object has also been linkedToDeath.
343 vib.mToken.unlinkToDeath(vib, 0);
344 }
345 }
346
347 private void updateInputDeviceVibrators() {
348 synchronized (mVibrations) {
349 doCancelVibrateLocked();
350
351 synchronized (mInputDeviceVibrators) {
352 mVibrateInputDevicesSetting = false;
353 try {
354 mVibrateInputDevicesSetting = Settings.System.getIntForUser(
355 mContext.getContentResolver(),
356 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
357 } catch (SettingNotFoundException snfe) {
358 }
359
360 if (mVibrateInputDevicesSetting) {
361 if (!mInputDeviceListenerRegistered) {
362 mInputDeviceListenerRegistered = true;
363 mIm.registerInputDeviceListener(this, mH);
364 }
365 } else {
366 if (mInputDeviceListenerRegistered) {
367 mInputDeviceListenerRegistered = false;
368 mIm.unregisterInputDeviceListener(this);
369 }
370 }
371
372 mInputDeviceVibrators.clear();
373 if (mVibrateInputDevicesSetting) {
374 int[] ids = mIm.getInputDeviceIds();
375 for (int i = 0; i < ids.length; i++) {
376 InputDevice device = mIm.getInputDevice(ids[i]);
377 Vibrator vibrator = device.getVibrator();
378 if (vibrator.hasVibrator()) {
379 mInputDeviceVibrators.add(vibrator);
380 }
381 }
382 }
383 }
384
385 startNextVibrationLocked();
386 }
387 }
388
389 @Override
390 public void onInputDeviceAdded(int deviceId) {
391 updateInputDeviceVibrators();
392 }
393
394 @Override
395 public void onInputDeviceChanged(int deviceId) {
396 updateInputDeviceVibrators();
397 }
398
399 @Override
400 public void onInputDeviceRemoved(int deviceId) {
401 updateInputDeviceVibrators();
402 }
403
404 private boolean doVibratorExists() {
405 // For now, we choose to ignore the presence of input devices that have vibrators
406 // when reporting whether the device has a vibrator. Applications often use this
407 // information to decide whether to enable certain features so they expect the
408 // result of hasVibrator() to be constant. For now, just report whether
409 // the device has a built-in vibrator.
410 //synchronized (mInputDeviceVibrators) {
411 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
412 //}
413 return vibratorExists();
414 }
415
416 private void doVibratorOn(long millis) {
417 synchronized (mInputDeviceVibrators) {
418 final int vibratorCount = mInputDeviceVibrators.size();
419 if (vibratorCount != 0) {
420 for (int i = 0; i < vibratorCount; i++) {
421 mInputDeviceVibrators.get(i).vibrate(millis);
422 }
423 } else {
424 vibratorOn(millis);
425 }
426 }
427 }
428
429 private void doVibratorOff() {
430 synchronized (mInputDeviceVibrators) {
431 final int vibratorCount = mInputDeviceVibrators.size();
432 if (vibratorCount != 0) {
433 for (int i = 0; i < vibratorCount; i++) {
434 mInputDeviceVibrators.get(i).cancel();
435 }
436 } else {
437 vibratorOff();
438 }
439 }
440 }
441
442 private class VibrateThread extends Thread {
443 final Vibration mVibration;
444 boolean mDone;
445
446 VibrateThread(Vibration vib) {
447 mVibration = vib;
448 mTmpWorkSource.set(vib.mUid);
449 mWakeLock.setWorkSource(mTmpWorkSource);
450 mWakeLock.acquire();
451 }
452
453 private void delay(long duration) {
454 if (duration > 0) {
455 long bedtime = duration + SystemClock.uptimeMillis();
456 do {
457 try {
458 this.wait(duration);
459 }
460 catch (InterruptedException e) {
461 }
462 if (mDone) {
463 break;
464 }
465 duration = bedtime - SystemClock.uptimeMillis();
466 } while (duration > 0);
467 }
468 }
469
470 public void run() {
471 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
472 synchronized (this) {
473 int index = 0;
474 long[] pattern = mVibration.mPattern;
475 int len = pattern.length;
476 int repeat = mVibration.mRepeat;
477 long duration = 0;
478
479 while (!mDone) {
480 // add off-time duration to any accumulated on-time duration
481 if (index < len) {
482 duration += pattern[index++];
483 }
484
485 // sleep until it is time to start the vibrator
486 delay(duration);
487 if (mDone) {
488 break;
489 }
490
491 if (index < len) {
492 // read on-time duration and start the vibrator
493 // duration is saved for delay() at top of loop
494 duration = pattern[index++];
495 if (duration > 0) {
496 VibratorService.this.doVibratorOn(duration);
497 }
498 } else {
499 if (repeat < 0) {
500 break;
501 } else {
502 index = repeat;
503 duration = 0;
504 }
505 }
506 }
507 mWakeLock.release();
508 }
509 synchronized (mVibrations) {
510 if (mThread == this) {
511 mThread = null;
512 }
513 if (!mDone) {
514 // If this vibration finished naturally, start the next
515 // vibration.
516 mVibrations.remove(mVibration);
517 unlinkVibration(mVibration);
518 startNextVibrationLocked();
519 }
520 }
521 }
522 };
523
524 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
525 public void onReceive(Context context, Intent intent) {
526 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
527 synchronized (mVibrations) {
528 doCancelVibrateLocked();
529
530 int size = mVibrations.size();
531 for(int i = 0; i < size; i++) {
532 unlinkVibration(mVibrations.get(i));
533 }
534
535 mVibrations.clear();
536 }
537 }
538 }
539 };
540 }
其中,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源码如下:
![](http://img0.tuicool.com/7JJJry.gif)
1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package android.os;
18
19 import android.util.Log;
20
21 /**
22 * Vibrator implementation that controls the main system vibrator.
23 *
24 * @hide
25 */
26 public class SystemVibrator extends Vibrator {
27 private static final String TAG = "Vibrator";
28
29 private final IVibratorService mService;
30 private final Binder mToken = new Binder();
31
32 public SystemVibrator() {
33 mService = IVibratorService.Stub.asInterface(
34 ServiceManager.getService("vibrator"));
35 }
36
37 @Override
38 public boolean hasVibrator() {
39 if (mService == null) {
40 Log.w(TAG, "Failed to vibrate; no vibrator service.");
41 return false;
42 }
43 try {
44 return mService.hasVibrator();
45 } catch (RemoteException e) {
46 }
47 return false;
48 }
49
50 @Override
51 public void vibrate(long milliseconds) {
52 if (mService == null) {
53 Log.w(TAG, "Failed to vibrate; no vibrator service.");
54 return;
55 }
56 try {
57 mService.vibrate(milliseconds, mToken);
58 } catch (RemoteException e) {
59 Log.w(TAG, "Failed to vibrate.", e);
60 }
61 }
62
63 @Override
64 public void vibrate(long[] pattern, int repeat) {
65 if (mService == null) {
66 Log.w(TAG, "Failed to vibrate; no vibrator service.");
67 return;
68 }
69 // catch this here because the server will do nothing. pattern may
70 // not be null, let that be checked, because the server will drop it
71 // anyway
72 if (repeat < pattern.length) {
73 try {
74 mService.vibratePattern(pattern, repeat, mToken);
75 } catch (RemoteException e) {
76 Log.w(TAG, "Failed to vibrate.", e);
77 }
78 } else {
79 throw new ArrayIndexOutOfBoundsException();
80 }
81 }
82
83 @Override
84 public void cancel() {
85 if (mService == null) {
86 return;
87 }
88 try {
89 mService.cancelVibrate(mToken);
90 } catch (RemoteException e) {
91 Log.w(TAG, "Failed to cancel vibration.", e);
92 }
93 }
94 }
说明 :
(01) 在构造函数SystemVibrator()中,我们通过 IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator")) 获取马达服务,实际上获取的是VibratorService对象。
(02) SystemVibrator的接口都是调用VibratorService接口实现的。
在讲解“应用层如何通过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中。
对马达服务而言,添加到哈希表SYSTEM_SERVICE_MAP中的key-value中的 key是VIBRATOR_SERVICE , value则是ServiceFetcher对象 ;而且该匿名ServiceFetcher对象的createService()方法会“通过new SystemVibrator()”返回SystemVibrator对象。而SystemVibrator我们在前面已经介绍过了,它是马达服务对外提供接口的类。
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对象。
由于fetcher不为null,所以,getSystemService()会返回fetcher.getService(this)。我们看看ServiceFetcher中getService()源码:
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对象”。
而在registerService()注册马达服务时,我们匿名实现了createService()方法:它实际上是通过 new SystemVibrator() 返回SystemVibrator对象。
至此,我们知道: getSystemService(VIBRATOR_SERVICE) 返回的是 SystemVibrator对象! SystemVibrator前面已经分析过,这里就不再说明了