GPS

来源:互联网 发布:电子签名算法 编辑:程序博客网 时间:2024/06/10 01:49

 

http://pp.sohu.com/member/wuhequan123

 

 


What is the role of WindowManager in android frame
I understand Windows manager is a separate service in the android
framework. I am wondering whether Window manager is like X Server or
not.
Lets say I have an activity with many views in it.
When an activity changes screen (i.e paint screen), Does it directly
draw on the drawing surface or request Window manager to draw on the
activity's behalf?
>>>
The window manager creates surfaces for the application, and applications
draw directly into those surfaces without going through the window manager.
>>>>>>
A surface is basically a pointer to block of memory. Why does a
separate process (i.e. Window Manager) have to create it? Why not the
activity itself create it?

Does Window manager need access to that memory?
If so, why?

>>>>>>>>>>>>

Because the window manager is responsible for organizing the screen,
applications don't get to decide that.  The window manager allocates
surfaces and decides where they go and how they are layered; it never
touches their bits, which is up to the application.


http://hi.baidu.com/zhouhanqing/blog/item/9d18a3cc16020a580eb3451c.html


Android面面观——Android事件处理下(按键、触摸屏和滚动球的一些实现细节)




对于按键事件,调用mDevices[i]->layoutMap->map进行映射。映射实际是由 KeyLayoutMap::map完成的,KeyLayoutMap类里读取配置文件qwerty.kl,由配置 文件 qwerty.kl 决定键值的映射关系。你可以通过修 改./development/emulator/keymaps/qwerty.kl来改变键值的映射关系。
JNI 函数

在frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp文件中,向 JAVA提供了函数android_server_KeyInputQueue_readEvent,用于读 取输入设备事件。

C代码

   1. static jboolean  
   2. android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,  
   3.                                            jobject event)  
   4. {  
   5.      gLock.lock();  
   6.      sp hub = gHub;  
   7.     if (hub == NULL) {  
   8.          hub = new EventHub;  
   9.          gHub = hub;  
  10.      }  
  11.      gLock.unlock();  
  12.  
  13.      int32_t deviceId;  
  14.      int32_t type;  
  15.      int32_t scancode, keycode;  
  16.      uint32_t flags;  
  17.      int32_t value;  
  18.      nsecs_t when;  
  19.     bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,  
  20.              &flags, &value, &when);  
  21.  
  22.      env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);  
  23.      env->SetIntField(event, gInputOffsets.mType, (jint)type);  
  24.      env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);  
  25.      env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);  
  26.      env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);  
  27.      env->SetIntField(event, gInputOffsets.mValue, value);  
  28.      env->SetLongField(event, gInputOffsets.mWhen,  
  29.                          (jlong)(nanoseconds_to_milliseconds(when)));  
  30.  
  31.     return res;  
  32. } 



readEvent调用hub->getEvent读了取事件,然后转换成JAVA的结构。
事件中转线程

在frameworks/base/services/java/com/android/server/KeyInputQueue.java 里创建了一个线程,它循环的读取事件,然后把事件放入事件队列里。

Java代码

   1. Thread mThread = new Thread("InputDeviceReader") {  
   2.         public void run() {  
   3.              android.os.Process.setThreadPriority(  
   4.                      android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);  
   5.  
   6.             try {  
   7.                  RawInputEvent ev = new RawInputEvent();  
   8.                 while (true) {  
   9.                      InputDevice di;  
  10.  
  11.                      readEvent(ev);  
  12.  
  13.                      send = preprocessEvent(di, ev);  
  14.                      addLocked(di, curTime, ev.flags, ..., me);  
  15.                  }  
  16.          }  
  17.      }; 


输入事件分发线程

在frameworks/base/services/java/com/android/server/WindowManagerService.java里创建了一个输入事件分发线程,它负责把事件分发到相应的窗口上去。

Java代码

   1. mQueue.getEvent  
   2. dispatchKey/dispatchPointer/dispatchTrackball 



按键,触摸屏流程分析

按键触摸屏流程分析:
WindowManagerService类的构造函数
WindowManagerService()
mQueue = new KeyQ();
因为 WindowManagerService.java (frameworks/base/services/java/com/android/server)中有:  
private class KeyQ extends KeyInputQueue
KeyQ 是抽象类 KeyInputQueue 的实现,所以 new KeyQ类的时候实际上在 KeyInputQueue 类中创建了
一个线程 InputDeviceReader 专门用来冲设备读取按键事件,代码:
Thread mThread = new Thread("InputDeviceReader") {
public void run()
{
        在循环中调用:readEvent(ev);
    ...
    send = preprocessEvent(di, ev);
        实际调用的是 KeyQ 类的 preprocessEvent 函数
    ...
    int keycode = rotateKeyCodeLocked(ev.keycode);
      int[] map = mKeyRotationMap;
      for (int i=0; i<N; i+=2)
      {
        if (map[i] == keyCode)
          return map[i+1];
      } //
    addLocked(di, curTime, ev.flags,RawInputEvent.CLASS_KEYBOARD,newKeyEvent(di, di.mDownTime, curTime, down,keycode, 0, scancode,...));
      QueuedEvent ev = obtainLocked(device, when, flags, classType, event);
}
}

readEvent() 实际上调用的是 com_android_server_KeyInputQueue.cpp (frameworks/base/services/jni)中的:
static jboolean android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,jobject event)
bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,&flags, &value, &when);
调用的是 EventHub.cpp (frameworks/base/libs/ui)中的:
bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
        int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
        int32_t* outValue, nsecs_t* outWhen)
在函数中调用了读设备操作:res = read(mFDs[i].fd, &iev, sizeof(iev));


在构造函数 WindowManagerService()调用 new KeyQ() 以后接着调用了:
mInputThread = new InputDispatcherThread();     
...   
mInputThread.start();
来启动一个线程 InputDispatcherThread
run()
process();
    QueuedEvent ev = mQueue.getEvent(...)
因为WindowManagerService类中: final KeyQ mQueue;
所以实际上 InputDispatcherThread 线程实际上从 KeyQ 的事件队列中读取按键事件。
switch (ev.classType)
case RawInputEvent.CLASS_KEYBOARD:
    ...
    dispatchKey((KeyEvent)ev.event, 0, 0);
    mQueue.recycleEvent(ev);
    break;
case RawInputEvent.CLASS_TOUCHSCREEN:
    //Log.i(TAG, "Read next event " + ev);
    dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
    break;

===============================================================


KeyInputQueue.java (frameworks/base/services/java/com/android/server):
的线程 Thread mThread = new Thread("InputDeviceReader") 本地调用:
readEvent(ev);读取按键。readEvent 调用的是文件:
com_android_server_KeyInputQueue.cpp (frameworks/base/services/jni)中的函数:
static jboolean android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
                                          jobject event)
android_server_KeyInputQueue_readEvent中有:
hub = new EventHub;
bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
            &flags, &value, &when);

hub->getEvent 调用的是
EventHub.cpp (frameworks/base/libs/ui) 文件中的函数:
bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
        int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
        int32_t* outValue, nsecs_t* outWhen)
读取按键。

class RefBase::weakref_impl : public RefBase::weakref_type



在系统启动后,android 会通过
static const char *device_path = "/dev/input";
bool EventHub::openPlatformInput(void)
res = scan_dir(device_path);


通过下面的函数打开设备。
int EventHub::open_device(const char *deviceName)
{
...
fd = open(deviceName, O_RDWR);
...
mFDs[mFDCount].fd = fd;
mFDs[mFDCount].events = POLLIN;
...
ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
...
const char* root = getenv("ANDROID_ROOT");
snprintf(keylayoutFilename, sizeof(keylayoutFilename),
                 "%s/usr/keylayout/%s.kl", root, tmpfn);
...
device->layoutMap->load(keylayoutFilename);
...
}
打开设备的时候,如果 device->classes&CLASS_KEYBOARD 不等于 0 表明是键盘。
常用输入设备的定义有:
enum {
        CLASS_KEYBOARD      = 0x00000001, //键盘
        CLASS_ALPHAKEY      = 0x00000002, //
        CLASS_TOUCHSCREEN   = 0x00000004, //触摸屏
        CLASS_TRACKBALL     = 0x00000008 //轨迹球
    };
打开键盘设备的时候通过上面的 ioctl 获得设备名称,命令字 EVIOCGNAME 的定义在文件:
kernel/include/linux/input.h 中。
#define EVIOCGNAME(len)   _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
在内核键盘驱动文件 drivers/input/keyboard/pxa27x_keypad.c 中定义了设备名称:pxa27x-keypad
static struct platform_driver pxa27x_keypad_driver = {
    .probe        = pxa27x_keypad_probe,
    .remove        = __devexit_p(pxa27x_keypad_remove),
    .suspend    = pxa27x_keypad_suspend,
    .resume        = pxa27x_keypad_resume,
    .driver        = {
        .name    = "pxa27x-keypad",
        .owner    = THIS_MODULE,
    },
};
ANDROID_ROOT 为环境变量,在android的命令模式下通过 printenv 可以知道它为: system
所以 keylayoutFilename 为:/system/usr/keylayout/pxa27x-keypad.kl
pxa27x-keypad.kl 定义了按键映射,具体内容如下:
----------------------
# NUMERIC KEYS 3x4
key 2   1
key 3   2
key 4   3
key 5   4
key 6   5
key 7   6
key 8   7
key 9   8
key 10 9
key 11 0
key 83 POUND
key 55 STAR

# FUNCTIONAL KEYS
key 231 MENU        WAKE_DROPPED
key 192 BACK           WAKE_DROPPED
key 193 HOME       WAKE
key 107 DEL        WAKE
key 102 CALL        WAKE_DROPPED
key 158 ENDCALL     WAKE_DROPPED
key 28   DPAD_CENTER     WAKE
key 115 VOLUME_UP
key 114 VOLUME_DOWN
----------------------
如果没有定义键盘映射文件,那么默认使用系统的 /system/usr/keylayout/qwerty.kl
可以修改 /system/usr/keylayout/qwerty.kl 文件改变Android公司的按键映射。

device->layoutMap->load(keylayoutFilename) 调用的是文件:
KeyLayoutMap.cpp (frameworks/base/libs/ui)中的函数:
status_t KeyLayoutMap::load(const char* filename)通过解析 pxa27x-keypad.kl
把按键的映射关系保存在 :KeyedVector<int32_t,Key> m_keys; 中。
当获得按键事件以后调用:
status_t KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags)
由映射关系 KeyedVector<int32_t,Key> m_keys 把扫描码转换成andorid上层可以识别的按键。

原创粉丝点击