Android之 看“马达”如何贯通Android系统 (从硬件设计 --> 驱动 --> HAL --> JNI --> Framework --> Application)

来源:互联网 发布:抽气真空袋知乎 编辑:程序博客网 时间:2024/06/05 18:31

原文

HAL (Hardware Abstraction Layer), 又称为“硬件抽象层”。在Linux驱动中,我们已经将马达设为映射为文件了;而该HAL层的存在的意义,就是 “对设备文件进行操作,从而相当于硬件进行操作 ”。HAL层的作用, 一是操作硬件设备 ,二是 操作接口封装,外界能方便的使用HAL提供的接口直接操作硬件设备。

理解了HAL之后,我们看看Android中如何在HAL层对马达进行操作。

在Android系统中,我们在libhardware_legacy中,实现马达的HAL层控制。 
马达在HAL中的代码路径: hardware/libhardware_legacy/vibrator/vibrator.c

vibrator.c的代码如下:

 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, software11  * 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 and14  * 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_HARDWARE31     if (qemu_check()) {32         return 1;33     }34 #endif35 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_HARDWARE49     if (qemu_check()) {50         return qemu_control_command( "vibrator:%d", timeout_ms );51     }52 #endif53 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 }
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的源码如下:

 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, software11  * 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 and14  * 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 android30 {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 };
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层的代码联系起来。 
以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_tracingSAVE_MAKEFILES := $(call all-named-subdir-makefiles,$(legacy_modules))LEGACY_AUDIO_MAKEFILES := $(call all-named-subdir-makefiles,audio)include $(SAVE_MAKEFILES)...LOCAL_MODULE:= libhardware_legacyinclude $(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_serversinclude $(BUILD_SHARED_LIBRARY)

Part 5 马达的Framework层实现

应用层操作马达,是通过马达服务进行操作的。而马达服务是通过aidl实现的,aidl是Android进程间的通信方式。关于aidl的更多说明可以参考“ Android Service总结06 之AIDL ”。

马达服务涉及的主要文件如下:

1 frameworks/base/services/java/com/android/server/SystemServer.java2 frameworks/base/services/java/com/android/server/VibratorService.java3 frameworks/base/core/java/android/os/IVibratorService.aidl4 frameworks/base/core/java/android/os/Vibrator.java5 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源码如下:

  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 simple110                 // vibration.111                 return false;112             }113             if ((mStartTime + mTimeout)114                     < (SystemClock.uptimeMillis() + millis)) {115                 // If this vibration will end before the time passed in, let116                 // 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 runtime125         // 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                     @Override148                     public void onChange(boolean selfChange) {149                         updateInputDeviceVibrators();150                     }151                 }, UserHandle.USER_ALL);152 153         mContext.registerReceiver(new BroadcastReceiver() {154             @Override155             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 a174         // timeout of 0 or negative. This will ensure that a vibration has175         // either a timeout of > 0 or a non-null pattern.176         if (milliseconds <= 0 || (mCurrentVibration != null177                 && mCurrentVibration.hasLongerTimeout(milliseconds))) {178             // Ignore this vibration since the current vibration will play for179             // 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 succeed209         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 fail221             if (pattern == null || pattern.length == 0222                     || 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 meant242                     // 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 succeed259         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 mVibrations284     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 mVibrations297     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 mVibrations307     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 be313             // called before startNextVibrationLocked or startVibrationLocked.314             mThread = new VibrateThread(vib);315             mThread.start();316         }317     }318 319     // Lock held on mVibrations320     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 in331         // 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     @Override390     public void onInputDeviceAdded(int deviceId) {391         updateInputDeviceVibrators();392     }393 394     @Override395     public void onInputDeviceChanged(int deviceId) {396         updateInputDeviceVibrators();397     }398 399     @Override400     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 vibrators406         // when reporting whether the device has a vibrator.  Applications often use this407         // information to decide whether to enable certain features so they expect the408         // result of hasVibrator() to be constant.  For now, just report whether409         // 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 duration481                     if (index < len) {482                         duration += pattern[index++];483                     }484 485                     // sleep until it is time to start the vibrator486                     delay(duration);487                     if (mDone) {488                         break;489                     }490 491                     if (index < len) {492                         // read on-time duration and start the vibrator493                         // duration is saved for delay() at top of loop494                         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 next515                     // 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 }
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源码如下:

 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, software11  * 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 and14  * 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  * @hide25  */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     @Override38     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     @Override51     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     @Override64     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 may70         // not be null, let that be checked, because the server will drop it71         // anyway72         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     @Override84     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 }
View Code

说明 : 
(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     @Override20     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             @Override31             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             @Override40             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     @Override54     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 @Override2 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前面已经分析过,这里就不再说明了

0 0
原创粉丝点击