Vibrator简单的流程介绍

Vibrator简单流程介绍

一,Vibrator结构流程

1.系统架构

2.流程图

二,Vibrator代码简单分析

 1.Activity应用层调用

 Vibrator vibrator = (Vibrator)getSysteService(VIBRATOR_SERVICE);
 vibrator.vibrate(50);

 2.如何获取Service服务

 Vibrator Service 对应关键字
 [路径:\frameworks\base\core\java\android\content\Context.java]
 /**
 * Use with {@link #getSystemService} to retrieve a {@link
 * android.os.Vibrator} for interacting with the vibration hardware.
 *
 * @see #getSystemService
 * @see android.os.Vibrator
 */
 public static final String VIBRATOR_SERVICE = "vibrator";


 利用VIBRATOR_SERVICE关键字,在ContextImpl.getSystemService(name)中获取对应的服务。
 说明:基本上各种服务的获取,都是在该处进行check并分取的。比如ACTIVITY_SERVICE、INPUT_METHOD_SERVICE等等。
 [路径:\frameworks\base\core\java\android\app\ContextImpl.java]
  ...
  } else if (VIBRATOR_SERVICE.equals(name)) {
      return getVibrator();
  } else if (STATUS_BAR_SERVICE.equals(name)) {
  ...
 private Vibrator getVibrator() {
    synchronized (mSync) {
        if (mVibrator == null) {
             mVibrator = new Vibrator();
        }
    }
    return mVibrator;
 }
 此处先通过ServiceManager获取一个Vibrator Service对应的Binder代理对象,再将该Binder代理对象做为IVibratorService.Stub.asInterface()的参数,并返回Vibrator的统一接口.
 [路径:\frameworks\base\core\java\android\os\Vibrator.java]
 public class Vibrator
 {
   private static final String TAG = "Vibrator";
   
   IVibratorService mService;
   private final Binder mToken = new Binder();
   
   /** @hide */
   public Vibrator()
   {
       mService = IVibratorService.Stub.asInterface(
               ServiceManager.getService("vibrator"));
   }
   ...
 }
 接下来分别看看ServiceManager.getService()和IVibratorService.Stub.asInterface

 IVibratorService.Stub.asInterface:

 IVibratorService.Stub.asInterface在IVibratorService.java中定义,这个IVibratorService.java代码可以由IVibratorService.aidl通过aidl工具自动生成的。aidl是一种android内部跨进程通讯接口的描述语言,即这里定义了跨进程的通讯接口描述。其对应的aidl描述如下:
 [路径:\frameworks\base\core\java\android\os\IVibratorService.aidl]
 interface IVibratorService
 {
   void vibrate(long milliseconds, IBinder token);
   void vibratePattern(in long[] pattern, int repeat, IBinder token);
   void cancelVibrate(IBinder token);
 }
 这里提供了三个接口函数:
   void vibrate(long milliseconds, IBinder token);
   void vibratePattern(in long[] pattern, int repeat, IBinder token);
   void cancelVibrate(IBinder token);
 这三个接口函数可以说就是Vibrator的全部控制概括。应用层通过上述三个接口函数,跨进程访问VibratorService。需要说明的是,接口参数必须与其service约定,保证顺序一致,保证service通过代理binder顺序读取。对于VibratorService的介绍,后面单独说,这里先讲解本进程的流程。
 下面我们回退到Vibrator JAVA框架中如何来调用上述三个接口函数的;
 在JAVA框架中,提供了如下几个函数,供应用层调用:
 //震动指定时间长度(单位ms),时间到后结束震动
 public void vibrate(long milliseconds);
 //震动间隔和周期可控的震动方式
 //pattern 数组,数组单数位置数字为等待时间,双数位置数字为震动时间
 //repeat 震动周期控制,-1为震动一个周期;0为一直震动,>0为重复pattern数组对应位置,必须repeat < pattern.length
 public void vibrate(long[] pattern, int repeat);
 public void cancel();
 
 由代码可以看出,应用层调用震动接口函数,实际上还是由aidl接口API通过代理binder对象去调用其service处理,知道最后驱动硬件。
    public void vibrate(long milliseconds)
   {
       if (mService == null) {
           Log.w(TAG, "Failed to vibrate; no vibrator service.");
           return;
       }
       try {
           mService.vibrate(milliseconds, mToken);
       } catch (RemoteException e) {
           Log.w(TAG, "Failed to vibrate.", e);
       }
   }
   public void vibrate(long[] pattern, int repeat)
   {
       if (mService == null) {
           Log.w(TAG, "Failed to vibrate; no vibrator service.");
           return;
       }
       // catch this here because the server will do nothing.  pattern may
       // not be null, let that be checked, because the server will drop it
       // anyway
       if (repeat < pattern.length) {
           try {
               mService.vibratePattern(pattern, repeat, mToken);
           } catch (RemoteException e) {
               Log.w(TAG, "Failed to vibrate.", e);
           }
       } else {
           throw new ArrayIndexOutOfBoundsException();
       }
   }
   public void cancel()
   {
       if (mService == null) {
           return;
       }
       try {
           mService.cancelVibrate(mToken);
       } catch (RemoteException e) {
           Log.w(TAG, "Failed to cancel vibration.", e);
       }
   }

 ServiceManager.getService():

 首先从sCache缓存中查看是否有对应的Binder对象,有则返回,没有则调用getIServiceManager().getService(name)获取一个vibrator Binder对象,其中getIServiceManager()用于返回系统中单独的ServiceManager对应的Binder代理对象。
 [路径:\frameworks\base\core\java\android\os\ServiceManager.java]
 /**
 * Returns a reference to a service with the given name.
 * 
 * @param name the name of the service to get
 * @return a reference to the service, or null if the service doesn't exist
 */
 public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return getIServiceManager().getService(name);
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
 }

 3.VibratorService的访问

 [路径:\frameworks\base\services\java\com\android\server\VibratorService.java]
 [路径:\frameworks\base\services\java\com\android\server\SystemServer.java]

 getIServiceManager()

 上面说到,在应用进程中通过getIServiceManager()获取系统中单独的ServiceManager对应的Binder,那如何获取的呢?
 当Zygote启动并初始化system时,会启动SystemServer系统服务,在SystemServer启动后,会创建一个线程,并在该线程中加载相关的服务,比如VibratorService。如下:
 public void run() {
   ...
   Slog.i(TAG, "Vibrator Service");
   ServiceManager.addService("vibrator", new VibratorService(context));
   ...
 }
 通过name,即可获取到对应的服务:
 ServiceManager.getService("vibrator")

VibratorService

 Android不能直接跨进程访问。在android中,Google创建了一个跨进程访问的方式---aidl方式,由aidl提供访问的接口函数。在应用层的访问方式,前面已经讲过,我们知道通过如下三个函数进行访问控制Vibrator:
   void vibrate(long milliseconds, IBinder token);
   void vibratePattern(in long[] pattern, int repeat, IBinder token);
   void cancelVibrate(IBinder token);
 那这三个函数是如何工作的呢?参考 VibratorService服务.基本的算法流程都在VibratorService.java中,可以自行跟踪调试。

 4.JNI调用

 但不管是何种方式开启震动或关闭震动,VibratorService都是通过JNI调用机制,调用本地框架(C/C++代码)中的接口。
   native static void vibratorOn(long milliseconds);
   native static void vibratorOff();
 
 [路径:\frameworks\base\services\jni\com_android_server_VibratorService.cpp]
 namespace android
 {
 
   static void vibratorOn(JNIEnv *env, jobject clazz, jlong timeout_ms)
   {
     // LOGI("vibratorOn\n");
     vibrator_on(timeout_ms);
   }
 
   static void vibratorOff(JNIEnv *env, jobject clazz)
   {
     // LOGI("vibratorOff\n");
     vibrator_off();
   }
 
   static JNINativeMethod method_table[] = {
     { "vibratorOn", "(J)V", (void*)vibratorOn },
     { "vibratorOff", "()V", (void*)vibratorOff }
   };
   
   int register_android_server_VibratorService(JNIEnv *env)
   {
     return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
         method_table, NELEM(method_table));
   }
 
 };
 其中对应的vibrator_on(timeout_ms)及vibratorOff()如下:
 [路径:\hardware\libhardware_legacy\vibrator\Vibrator.c]
 #define THE_DEVICE "/sys/class/timed_output/vibrator/enable"
 
 static int sendit(int timeout_ms)
 {
     int nwr, ret, fd;
     char value[20];
 
 #ifdef QEMU_HARDWARE
     if (qemu_check()) {
         return qemu_control_command( "vibrator:%d", timeout_ms );
     }
 #endif
 
     fd = open(THE_DEVICE, O_RDWR);
     if(fd < 0)
         return errno;
 
     nwr = sprintf(value, "%d\n", timeout_ms);
     ret = write(fd, value, nwr);
 
     close(fd);
 
     return (ret == nwr) ? 0 : -1;
 }
 
 int vibrator_on(int timeout_ms)
 {
     /* constant on, up to maximum allowed time */
     return sendit(timeout_ms);
 }
 
 int vibrator_off()
 {
     return sendit(0);
 }
 其中实现的核心内容为sendit()函数,它负责根据时间“震动”,通过读写sys文件系统的设备文件进行控制;
 在android中,是基于Android内核定义Timed Output驱动程序框架来实现Vibrator的驱动程序。Timed Output的含义为定时输出,用于定时发出某个输出。
 Timed Output驱动程序框架为每个设备在 /sys/class/timed_output/目录下建立一个子目录,设备子目录的enable文件就是设备的控制文件。读enable文件表示获取剩余的时间,写这个文件表示根据时间震动。
 对于Vibrator设备,其实现的Timed Output驱动程序的名称应该为"vibrator"

 三,直接控制Vibrator

 其实我们可以通过直接读写该文件系统来控制vibrator:
     1. 用USB线连接手机与PC,保证连接正常。
     2. 打开cmd.exe,路径切换到\android-sdk-windows\tools\
     3. 敲入: adb shell,回车,进入shell控制模式
     4. 敲入: echo "2000" > sys/class/timed_output/vibrator/enable,回车,设置手机震动20s
     5. 敲入: cat sys/class/timed_output/vibrator/enable, 回车,显示震动剩余时间

你可能感兴趣的:(Vibrator简单的流程介绍)