原文地址:

http://www.cnblogs.com/simonshi/archive/2010/03/22/1691984.html

在系统启动过程中,会加载驱动程序,初始化硬件设备,会进入bool EventHub::openPlatformInput(void)这个函数,该函数主要功能是扫描/dev/input该目录,获取输入设备。如何获取呢?通过linux API res = scan_dir(device_path); 该函数叫

while((de = readdir(dir))) {

strcpy(filename, de->d_name);

open_device(devname);

}

不断读取目录文件,然后通过open_device()打开设备。具体打开设备函数是fd = open(deviceName, O_RDWR);以读写方式打开,该函数会调用驱动里file_operations里的实现函数。

此时所有输入设备已经打开。

在WindowManagerService服务类运行的时候,在构造函数中会创建内部类KeyQ对象. 该类继承之KeyInputQueue类。当然要进入该类的构造函数。在KeyInputQueue类的构造函数中会启动Thread mThread=new Thread("InputDeviceReader")这个匿名内部类线程,有该线程读驱动事件并把它放到消息队列中。具体实现是:

Thread mThread = new Thread("InputDeviceReader") {

public void run() {

RawInputEvent ev = new RawInputEvent();

while (true) {

InputDevice di;

readEvent(ev);

}

}

该线程持续运行,循环通过readEvent(); 该函数是个native方法,具体实现为

static jboolean

android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,

jobject event)

{

gLock.lock();

sp<EventHub> hub = gHub;

if (hub == NULL) {

hub = new EventHub;

gHub = hub;

}

gLock.unlock();

int32_t deviceId;

int32_t type;

int32_t scancode, keycode;

uint32_t flags;

int32_t value;

nsecs_t when;

bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,

&flags, &value, &when);

}

以上步骤获得了事件QueuedEvent。

获得事件后通过

private void addLocked(InputDevice device, long when, int flags,

int classType, Object event) {

boolean poke = mFirst.next == mLast;

QueuedEvent ev = obtainLocked(device, when, flags, classType, event);

QueuedEvent p = mLast.prev;

while (p != mFirst && ev.when < p.when) {

p = p.prev;

}

ev.next = p.next;

ev.prev = p;

p.next = ev;

ev.next.prev = ev;

ev.inQueue = true;

}

该函数加到消息队列中,该消息队列就是个双向连表,头和尾分别是 final QueuedEvent mFirst;

final QueuedEvent mLast; 该函数就是把新消息插到尾的前面。

消息队列有了。还需要读队列。在WindowManagerService.java 类中同时又开了个内部线程

mInputThread = new InputDispatcherThread();

mInputThread.start();

该线程和刚才的写队列线程是并行的。该线程起来后,通过

public void run() {

while (true) {

try {

process();

} catch (Exception e) {

Log.e(TAG, "Exception in input dispatcher", e);

}

}

}

这个process()函数来读消息。具体实现是

private void process() {

android.os.Process.setThreadPriority(

android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);

while (true) {

QueuedEvent ev = mQueue.getEvent(

(int)((!configChanged && curTime < nextKeyTime)

? (nextKeyTime-curTime) : 0));

}

该getEvent()函数的具体实现是

QueuedEvent getEvent(long timeoutMS) {

long begin = SystemClock.uptimeMillis();

final long end = begin+timeoutMS;

long now = begin;

synchronized (mFirst) {

while (mFirst.next == mLast && end > now) {

QueuedEvent p = mFirst.next;

mFirst.next = p.next;

mFirst.next.prev = mFirst;

p.inQueue = false;

return p;

}

}

持续的读消息,如果没消息就阻塞,有消息,就读取消息,所谓读取消息就得到引用,然后把该消息从双向连表中删除。得到消息后根据消息输入设备类型把消息发送到具体AP 中。如

switch (ev.classType) {

case RawInputEvent.CLASS_KEYBOARD:

dispatchKey((KeyEvent)ev.event, 0, 0);

mQueue.recycleEvent(ev);

break;

case RawInputEvent.CLASS_TOUCHSCREEN:

dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);

break;

case RawInputEvent.CLASS_TRACKBALL:

dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);

break;

case RawInputEvent.CLASS_CONFIGURATION_CHANGED:

configChanged = true;

break;

default:

mQueue.recycleEvent(ev);

break;

}

当然这其中涉及很多细节,有兴趣可以看看。同时读写队列的互斥机制也值得学习。

更多相关文章

  1. Android(java)回调函数经典示例
  2. android中View, Window, Activity, WindowManager,ViewRoot几者之
  3. [Android] [SystemUI] Recent -- 最近任务的启动流程
  4. FFmpeg编译MediaCodec
  5. Android(安卓)FFmpeg系列——4 子线程播放音视频
  6. Android(安卓)Audio AudioStreamOutALSA::write函数
  7. Android(安卓)Timer 分析
  8. android企业开发学习——handler
  9. 阅读Android消息机制源码的随手笔记

随机推荐

  1. Android的onCreateOptionsMenu()创建菜单
  2. Android百分比布局
  3. Mac系统cocos2dx + android 开发环境配置
  4. android BitMap回收
  5. Android AES加密解密
  6. android从资源文件中读取文件流显示
  7. android studio的Gradle各种配置汇总
  8. Android(安卓)破解apk文件
  9. 第四周
  10. android数据单位dp,px和sp