您的位置:首页 > 移动开发 > Android开发

Android输入事件读入流程

2011-04-28 19:04 218 查看
 

一.从SystemService.java中启动服务

     代码路径:frameworks/base/services/java/com/android/server/SystemServer.java

      public class SystemServer

      {

         .....

         native public static void init1(String[] args);

        

         public static void main(String[] args) {

         .........

         init1(args);

       }

       public static final void init2() {

        Slog.i("yaojuntaoSystemServer", "Entered the Android system server!");

        Thread thr = new ServerThread();

        thr.setName("android.server.ServerThread");

        thr.start();

      }

      }

调用init1(args),初始化显示系统,音频等,init1通过JNI调用到com_android_server_SystemServer.cpp

的static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz),而android_server_SystemServer_init1会调用system_init();

system_init()将调用在 System_init.cpp 中

extern "C" status_t system_init()

{

......

runtime->callStatic("com/android/server/SystemServer",

SystemService.java 中的 init2。

......

}

 

在init2中会建立一个服务线程,我们可以看一下:

class ServerThread extends Thread {

...

public void run()

{

...

wm = WindowManagerService.main(context, power,

                    factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);

            ServiceManager.addService(Context.WINDOW_SERVICE, wm);

            ((ActivityManagerService)ServiceManager.getService("activity"))

                    .setWindowManager(wm);

...

}

}

在这个线程中调用了很多的service,我们主要关注的是WindowMangerService接下来跳转到
WindowMangerService
分析。

 

二.
WindowMangerService

代码路径:services/java/com/android/server/WindowManagerService.java

 


SystemService.java调到WindowManagerService 的main方法:

public static WindowManagerService main(Context context,

            PowerManagerService pm, boolean haveInputMethods) {

        WMThread thr = new WMThread(context, pm, haveInputMethods);

        thr.start();

        Slog.e("yaojuntaoWindowManagerService","WindowManagerService thr ok");

        synchronized (thr) {

            while (thr.mService == null) {

                try {

                    thr.wait();

                } catch (InterruptedException e) {

                }     

            }     

        }     

      

        return thr.mService;

    }

在main中建立了线程:

static class WMThread extends Thread {

..

 public void run() {

...

WindowManagerService s = new WindowManagerService(mContext, mPM,

                    mHaveInputMethods);

...

}

建立了 WindowManagerService的对象,将跳到构造函数:

 private WindowManagerService(Context context, PowerManagerService pm,

            boolean haveInputMethods) {

........

int max_events_per_sec = 35;

        try {

            max_events_per_sec = Integer.parseInt(SystemProperties

                    .get("windowsmgr.max_events_per_sec"));

            if (max_events_per_sec < 1) {

                max_events_per_sec = 35;

            }     

        } catch (NumberFormatException e) {

        }     

        mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;

         private WindowManagerService(Context context, PowerManagerService pm,

            boolean haveInputMethods) {

mQueue = new KeyQ();

        mInputThread = new InputDispatcherThread();

        PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);

        thr.start();

.........

}

在该段代码中我们看到mQueue = new KeyQ(),该句建立了输入的队列,通过这个去读底部传上来的数据,我们暂时不向下看,在mInputThread = new InputDispatcherThread()一句中建立了数据的分发线程,我们来看一下:

private final class InputDispatcherThread extends Thread {

......

public void run() {

while (true) {

                try {

                    process();

                } catch (Exception e) {

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

                }

            }

        }

....

}

调用了 process(),好,继续看 process():

private void process() {

....

while (true) {

....

 

QueuedEvent ev = mQueue.getEvent(

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

                            ? (nextKeyTime-curTime) : 0));

......

}

}

我们看到在process()中进入了循环,在循环中调用mQueue.getEvent从queue中获得数据并分发,mQueue这个对象在上面建立的,我们会看到这个对象的方法与属性,在此我们可以看到输入的上层的流程,紧接着向下走。

三.KeyInputQueue.java

 

代码:services/java/com/android/server/KeyInputQueue.java

在上次提到mQueue = new KeyQ();这行,而在WindowMangerService中有:

private class KeyQ extends KeyInputQueue,然后我们找到
KeyInputQueue的构造函数:

KeyInputQueue(Context context, HapticFeedbackCallback  hapticFeedbackCallback) {

.....

mThread.start();

....

}

我们看一下
mThread这个线程:

Thread mThread = new Thread("InputDeviceReader") {

        public void run() {

...

while (true) {

                try {

                    InputDevice di;

                    // block, doesn't release the monitor

                    readEvent(ev);

....

}

}

}}

可以看到在该线程中循环通过
readEvent(ev)去读事件,而private static native boolean readEvent(RawInputEvent outEvent)说明调用为JNI中的函数,另为我们发现QueuedEvent getEvent(long timeoutMS) 方法被调用时,值传了上去。

 

四.JNI

代码:

services/jni/com_android_server_KeyInputQueue.cpp


com_android_server_KeyInputQueue.cpp中我们发现了:

static jboolean

android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,

                                          jobject event)

{

....

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

            &flags, &value, &when);

.....

}

我们来看
hub->getEven,代码路径在libs/ui/EventHub.cpp

 

bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,

        int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,

        int32_t* outValue, nsecs_t* outWhen)

{

....

 if (!mOpened) {

        mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;

        mOpened = true;

    }  

......

}

penPlatformInput()将扫描/dev/input 下的所有 event 并打开它

bool EventHub::openPlatformInput(void)

{

......

res = scan_dir(device_path);//其中 static const char *device_path = "/dev/input";

......

}



int EventHub::scan_dir(const char *dirname)

{

char devname[PATH_MAX];

char *filename;

DIR *dir;

struct dirent *de;

dir = opendir(dirname);

if(dir == NULL)

return -1;

strcpy(devname, dirname);

filename = devname + strlen(devname);

*filename++ = '/';

//扫描/dev/input 下的所有 event 并打开它

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

if(de->d_name[0] == '.' &&

(de->d_name[1] == '/0' ||

(de->d_name[1] == '.' && de->d_name[2] == '/0')))

continue;

strcpy(filename, de->d_name);

open_device(devname);//打开 event 设备

}

closedir(dir);

return 0;

}

int EventHub::open_device(const char *deviceName)

{

......

fd = open(deviceName, O_RDWR);

......

}

如果上面的操作都成功则把所有设备都打开了,现回到 EventHub::getEvent。

release_wake_lock(WAKE_LOCK_ID);

pollres = poll(mFDs, mFDCount, -1);

acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

在这边 poll,如果没有新事件将在这等待,如果有则开始下面的读事件

res = read(mFDs[i].fd, &iev, sizeof(iev));

到此整个从上面开始的读过程结束。

 

到此Android的输入流程已结束,接下来会详细刨析输入的细节。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息