android学习笔记5 android按键事件处理代码走读[framework]

来源:互联网 发布:淘宝刷流量 猎流 编辑:程序博客网 时间:2024/04/30 01:54

上层的对按键事件的侦听和纷发处理是通过inputmanager及其组件inputreader,inputdispatch,eventhub构成的。

在system_server被创建的时候就会创建WMS,并调用inputmanager的start方法来启动read和dispatch线程。

 

1.      Inputmanager的创建

Systemserver的ServerThread的run函数中,会调用WMS的main方法来创建WMS

          Slog.i(TAG, "WindowManager");

            wm = WindowManagerService.main(context,power,

factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);

           ServiceManager.addService(Context.WINDOW_SERVICE, wm);

再来看windowmanagerservice的main方法:

   public static WindowManagerServicemain(Context context,

            PowerManagerService pm, booleanhaveInputMethods) {

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

        thr.start();

 

        synchronized (thr) {

            while (thr.mService == null) {

                try {

                    thr.wait();

                } catch (InterruptedExceptione) {

                }

            }

        }

 

        return thr.mService;

}此方法很简单,就是创建了WMThread,然后调用了他的start方法。

继续看WMThread:它的构造函数很简单,就是给几个变量赋值,重点看看它的run函数:

        public void run() {

            Looper.prepare();

            WindowManagerService s = new WindowManagerService(mContext, mPM,

                    mHaveInputMethods);

            android.os.Process.setThreadPriority(

                   android.os.Process.THREAD_PRIORITY_DISPLAY);

           android.os.Process.setCanSelfBackground(false);

 

            synchronized (this) {

                mService = s;

                notifyAll();

            }

 

            Looper.loop();

        }

此方法创建了WMS的实例,继续跟进:

    private WindowManagerService(Contextcontext, PowerManagerService pm,

            boolean haveInputMethods) {

//……..省略无关代码

        mInputManager = newInputManager(context, this);

//……

}

看看inputmanager的构造函数:inputmanager.java中

    public InputManager(Context context,WindowManagerService windowManagerService) {

        this.mContext = context;

        this.mWindowManagerService =windowManagerService;

       

        this.mCallbacks = new Callbacks();

       

        init();

   }

就是给几个变量赋值,调用了init :

    private void init() {

        Slog.i(TAG, "Initializing inputmanager");

        nativeInit(mCallbacks);

   }

调用nativeInit ,此方法对应了com_android_server_inputmanager.java中的

android_server_InputManager_nativeInit(sourceinsight搜一下即可,就是inputmanger对应的JNI的部分。)

staticvoid android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,

        jobject callbacks) {

    if (gNativeInputManager == NULL) {

       gNativeInputManager = new NativeInputManager(callbacks);

    } else {

        LOGE("Input manager alreadyinitialized.");

        jniThrowRuntimeException(env,"Input manager already initialized.");

    }

}此方法也是直接调用了NativeInputManager的构造函数:

NativeInputManager::NativeInputManager(jobjectcallbacksObj) :

    mFilterTouchEvents(-1),mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),

    mMaxEventsPerSecond(-1),

    mDisplayWidth(-1), mDisplayHeight(-1),mDisplayOrientation(ROTATION_0) {

    JNIEnv* env = jniEnv();

 

    mCallbacksObj =env->NewGlobalRef(callbacksObj);

 

    sp<EventHub> eventHub = new EventHub();

    mInputManager = new InputManager(eventHub,this, this);

}此方法中做了两件很重要的事情,创建了EventHub并将其作为入参传入了InputManager,此处的inputmanager是native的,即是inputmanager.cpp中的。

Inputmanager.cpp  

InputManager::InputManager(

        const sp<EventHubInterface>&eventHub,

        const sp<InputReaderPolicyInterface>&readerPolicy,

        constsp<InputDispatcherPolicyInterface>& dispatcherPolicy) {

    mDispatcher = new InputDispatcher(dispatcherPolicy);

    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);

    initialize();

}创建了inputdispatcher和inputreader,并调用了initialize函数创建了InputReaderThread和InputDispatcherThread。

到这里,相关的组件就创建完毕了,那么这些进程是怎么跑取来的呢?

2.      关键线程的启动:

我们还是回到WMS的构造函数中:

    private WindowManagerService(Contextcontext, PowerManagerService pm,

            boolean haveInputMethods) {

         //。。。。。。省略

        mInputManager = new InputManager(context, this);

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

        thr.start();

 

        synchronized (thr) {

            while (!thr.mRunning) {

                try {

                    thr.wait();

                } catch (InterruptedExceptione) {

                }

            }

        }

 

        mInputManager.start();

创建完毕后,就会调用inputmanager的start函数,过程和creat相当的类似,都是用过JNI的调用到native的线程启动,下面依然一级一级的跟,首先是inputmanager的start:

   public void start() {

        Slog.i(TAG, "Starting inputmanager");

        nativeStart();

   }

直接调用了nativeStart,对应的是com_android_server_inputmanager.java中的

android_server_InputManager_nativeStart

staticvoid android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {

    if (checkInputManagerUnitialized(env)) {

        return;

    }

 

    status_tresult = gNativeInputManager->getInputManager()->start();

    if (result) {

        jniThrowRuntimeException(env,"Input manager could not be started.");

    }

}

gNativeInputManager即是上面在创建的时候,通过NativeInputManager的构造函数获取的,而getInputManager的声明为:

   inline sp<InputManager> getInputManager() const { returnmInputManager; }

 

直接返回mInputManager,而mInputManager也是在NativeInputManager的构造函数调用的。所以,实际调用的应该是native的inputmanager的start函数:

Inputmanager.cpp

status_tInputManager::start() {

    status_t result = mDispatcherThread->run("InputDispatcher",PRIORITY_URGENT_DISPLAY);

    if (result) {

        LOGE("Could not startInputDispatcher thread due to error %d.", result);

        return result;

    }

 

    result = mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY);

    if (result) {

        LOGE("Could not start InputReaderthread due to error %d.", result);

 

        mDispatcherThread->requestExit();

        return result;

    }

 

    return OK;

}

到这里,这两个线程就跑起来了,mDispatcherThread负责按键事件的纷发。mReaderThread负责按键事件的获取,接下来用power键的处理作为一个例子,来过下按键事件的简单流程。

3.      按键捕获:

mReaderThread->run后会走到他的threadLoop函数:

boolInputReaderThread::threadLoop() {

    mReader->loopOnce();

    return true;

}

调用了inputreader的looponce函数:

voidInputReader::loopOnce() {

   RawEvent rawEvent;

    mEventHub->getEvent(& rawEvent);

 

#ifDEBUG_RAW_EVENTS

    LOGD("Input event: device=0x%xtype=0x%x scancode=%d keycode=%d value=%d",

            rawEvent.deviceId, rawEvent.type,rawEvent.scanCode, rawEvent.keyCode,

            rawEvent.value);

#endif

 

    process(& rawEvent);

}

首先是从eventhub中获取事件,再将其传入process中,eventhub的工作机理还没搞清楚,将在下一篇中分析。

根据返回的rawevent中的类型,会做不同的处理:

voidInputReader::process(const RawEvent* rawEvent) {

    switch (rawEvent->type) {

    case EventHubInterface::DEVICE_ADDED:

        addDevice(rawEvent->deviceId);

        break;

 

    case EventHubInterface::DEVICE_REMOVED:

        removeDevice(rawEvent->deviceId);

        break;

 

    caseEventHubInterface::FINISHED_DEVICE_SCAN:

       handleConfigurationChanged(rawEvent->when);

        break;

 

    default:

        consumeEvent(rawEvent);

        break;

    }

}

如果是power键,会走到consumeEvent

 

 

 

 

 

 

 

voidInputReader::consumeEvent(const RawEvent* rawEvent) {

    int32_t deviceId = rawEvent->deviceId;

 

    { // acquire device registry reader lock

        RWLock::AutoRLock_rl(mDeviceRegistryLock);

 

        ssize_t deviceIndex = mDevices.indexOfKey(deviceId);

        if (deviceIndex < 0) {

            LOGW("Discarding event forunknown deviceId %d.", deviceId);

            return;

        }

 

        InputDevice* device =mDevices.valueAt(deviceIndex);

        if (device->isIgnored()) {

            //LOGD("Discarding event forignored deviceId %d.", deviceId);

            return;

        }

 

        device->process(rawEvent);

    } // release device registry reader lock

}通过刚刚传入的diviceid找到对应的deviceindex,而这些device的创建和销毁正是上步中的ADD/REMOVEdevice 。

最后调用device的process

voidInputDevice::process(const RawEvent* rawEvent) {

    size_t numMappers = mMappers.size();

    for (size_t i = 0; i < numMappers; i++){

        InputMapper* mapper = mMappers[i];

        mapper->process(rawEvent);

    }

}调用在creatdevice时添加的mapper的process,我们这里是power键,所以应该是KeyboardInputMapper(详见creatdevice函数)

voidKeyboardInputMapper::process(const RawEvent* rawEvent) {

    switch (rawEvent->type) {

    case EV_KEY: {

        int32_t scanCode =rawEvent->scanCode;

        if (isKeyboardOrGamepadKey(scanCode)) {

            processKey(rawEvent->when,rawEvent->value != 0, rawEvent->keyCode, scanCode,

                    rawEvent->flags);

        }

        break;

    }

    }

}

通过判断scan code,确认是否为键盘或者游戏手柄,如果是则走到processkey:

voidKeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,

       int32_t scanCode, uint32_t policyFlags) {

   int32_t newMetaState;

   nsecs_t downTime;

   bool metaStateChanged = false;

 

{ // ……省略此处对按键的处理

 

    getDispatcher()->notifyKey(when,getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,

            down ? AKEY_EVENT_ACTION_DOWN :AKEY_EVENT_ACTION_UP,

            AKEY_EVENT_FLAG_FROM_SYSTEM,keyCode, scanCode, newMetaState, downTime);

此处就会通知dispatch,有按键上报。

voidInputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,

        uint32_t policyFlags, int32_t action,int32_t flags,

        int32_t keyCode, int32_t scanCode,int32_t metaState, nsecs_t downTime) {

      //,,,,,….

 

    mPolicy->interceptKeyBeforeQueueing(eventTime,deviceId, action, /*byref*/ flags,

            keyCode, scanCode, /*byref*/policyFlags);

此处的mPolicy就是创建inputdispatch的时候传入的,可以看出,这个mPolicy就是NativeInputManager的this。(NativeInputManager::NativeInputManager创建native的inputmanager的时候传入)

所以,此处的interceptKeyBeforeQueueing实际是NativeInputManager的interceptKeyBeforeQueueing:

而在此函数中会调用WMS的interceptKeyBeforeQueueing,询问其是否会对此按键做特殊处理,实际是在phonewindowmanager中处理的,接下来的流程已经在上一篇中讲过,不再赘述,下一篇中打算将eventhub的流程,尤其是按键扫描的对应搞清楚。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 眼睛不小心捅伤怎么办 我的爸爸是小偷怎么办 违停罚款忘记交怎么办 顺风车无人接单怎么办 来例假腰特别疼怎么办 把人撞死了全责怎么办 朝鲜与美合作对付中国怎么办 申请美国大学gpa不够怎么办 武装突袭3有地雷怎么办 辐射4狗肉跟丢了怎么办 洛奇英雄传死绑S怎么办 在老挝遇到坏人带枪怎么办 买了sd卡卡槽塞不下怎么办 现役军人家庭被邻居欺服怎么办 地铁买票买多了怎么办 免税店买的东西转机怎么办 绿能电动车坏了怎么办? 永久单车收不到验证码怎么办 24速山地车档乱了怎么办 新电瓶车被偷了怎么办 汽车前风挡玻璃砸出洞怎么办 凯迪拉克xt5钥匙掉了怎么办 凯迪拉克xt5媒体不好用怎么办 晒黄的白鞋怎么办 白鞋子被晒黄了怎么办? 耐克空军一号白色发黄怎么办 空军一号破皮了怎么办 匡威鞋帆布破了怎么办 脚腕起疙瘩很痒怎么办 跑步后脚踝微疼怎么办 跑步跑得脚疼怎么办 nike air 鞋头脱胶怎么办 耐克空军一号磨脚怎么办 白鞋刷完变黄了怎么办 乔丹气垫坏了怎么办 气垫鞋气垫坏了怎么办 建行u盾忘记密码怎么办 工商银行u盾忘记密码怎么办 民生银行不给u盾怎么办 银行不给开u盾怎么办 有车有空想赚点外快怎么办