View机制深入学习(五) 事件处理机制一

本文深入探讨Android的事件处理机制,从事件的获取、InputManagerService的启动,到事件的分发过程。详细介绍了从事件源采集、前期处理、WMS分配,再到应用程序处理的整个流程,包括InputDispatcher和InputReader的角色,以及InputChannel在View和ViewGroup中的作用。通过对InputEvent接口、KeyEvent和MotionEvent的分析,揭示了Android系统如何处理和传递不同类型的输入事件。
摘要由CSDN通过智能技术生成

以TouchEvent为主,看一下View和ViewGroup内部是如何处理Input Events的;
首先来看事件的产生来源:

一、获取事件:

事件的来源可以分为“软件”,“硬件”两种;
主要的事件包含有:
按键事件(KeyEvent) :即物理按键按下产生的事件,相关的常用物理按键一般有HOME,BACK等
触摸事件(TouchEvent):
鼠标事件(MouseEvent)、轨迹球事件(TrackBallEvent)(这两个已经不常见);

针对所有事件的共性抽象出了InputEvent接口;其有两个子类:KeyEvent,MotionEvent;

1、事件的投递流程:

这里写图片描述

1>源信息采集
对“硬件源”产生的原始信息进行收集;它需要Linux内核驱动的支持,Android系统通过/dev/input下的节点来访问当前发生的事件。
2>前期处理
对收集到信息进行筛选以及格式转化
3>WMS分配
WMS是窗口的Manager,同时也是InputEvent的派发者。
4>应用程序处理
WMS会先把事件传递到对应ViewRootImpl,ViewRootImpl分发事件,传递给相应的DecorView,DecorView在调用Activity中的Window.Callback将事件传递给Activity;然后Activity在通过dispatchTouchEvent分发事件,下面就来到熟悉的View事件分发机制;具体见《View机制深入学习(四)View的事件分发机制》

2、InputManagerService启动:

InputManagerService同样也是有SystemServer进程启动,这个在Android启动过程——init.rc,Zygote,SystemServer中已经提到过,
系统启动后创建init进程(pid=1),init进程创建出Zygote进程,然后Zygote进程孵化出SystemServer进程,在SystemServer进程中创建IMS:

/** @path: \frameworks\base\services\java\com\android\server\SystemServer.java */
class ServerThread extends Thread {
    @Override
    public void run() {
        // 可以看到IMS和WMS是紧密相关的
        ......
        // @value InputManagerService inputManager
        inputManager = new InputManagerService(context, wmHandler);

        Slog.i(TAG, "Window Manager");
        // @value WindowManagerService wm
        wm = WindowManagerService.main(context, power, display, inputManager,
                uiHandler, wmHandler,
                factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
                !firstBoot, onlyCore);
        ServiceManager.addService(Context.WINDOW_SERVICE, wm);
        ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

        ActivityManagerService.self().setWindowManager(wm);

        inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
        inputManager.start();
        .....
    }
}

3、InputMangerService:

/** \frameworks\base\services\core\java\com\android\server\input\InputManagerService.java **/
public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
   
    // 指向native端IMS类对象的地址
    private final long mPtr;

    public InputManagerService(Context context) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

        mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);

        // 创建native IMS对象
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }
}

可以看到Java层的IMS实际上只是对Native层的InputManager的一层包装;其创建主要是native层进行创建,并把native层的InputManager地址赋值给InputManagerService的mPtr变量;
而且注意nativeInit中传入了Looper中的MessageQueue变量;

4、native层的InputManagerService——NativeInputManager类:

/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface

static jlong nativeInit(JNIEnv* env, jclass clazz,
                        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    // 创建一个Message Queue
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    // 可以看到NativeInputManager中包含有一个Looper,用以进行事件分派
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    // 返回创建的IMS实例对象的地址(强制转化为long类型)
    return reinterpret_cast<jlong>(im);
}

可以看到首先通过android_os_MessageQueue_getMessageQueue函数获取到本地端的MessageQueue,这个在Handler机制中的本地解析《Handler机制深入解析》中已经提到,该NativeMessageQueue对象在java层创建Looper时创建实例,然后将地址指针赋值为Looper对应的MessageQueue中的ptr变量中,这里根据指针来获取该NativeMessageQueue对象;
根据NativeMessageQueue对象获取其中对应的Looper(native),用以创建NativeInputManger;来看NativeInputManager的构造函数:

5、NativeInputManager#NativeInputManager:

/** \frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp **/
NativeInputManager::NativeInputManager(jobject contextObj,
                                       jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    // 全局引用
    mContextObj = env->NewGlobalRef(contextObj);
    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
    }

    // 创建EventHUb
    sp<EventHub> eventHub = new EventHub();
    // 创建InputManager实例
    mInputManager = new InputManager(eventHub, this, this);
}

NativeInputManager中保存了Looper(native)实例;并且创建了EventHub,以及InputManager两个重要的对象;
EventHub从名字就可以看出,它是用来收集以及存储外部的输入事件的;
而InputManager则是对Event事件进行处理分发;
先来看EventHub:

(一)EventHub:

/*\frameworks\native\services\inputflinger\EventHub*/
static const char *DEVICE_PATH = "/dev/input";
EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(0), mClosingDevices(0),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

    // 创建epoll对象
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);

    // 采用inotify机制监听文件或目录的移动、读取、写入或删除等事件
    // 创建一个inotify对象
    mINotifyFd = inotify_init();
    // 把监控项添加到mINotifyFd对象的监控列表中
    // 这里监听的文件路径为"/dev/input"
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = EPOLL_ID_INOTIFY;
    // 把inotify对象mINotifyFd添加到epoll对象的兴趣列表中,此处采用inotify与epoll机制结合起来检查文件
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);

    int wakeFds[2];
    // 创建pipe
    result = pipe(wakeFds);

    mWakeReadPipeFd = wakeFds[0];
    mWakeWritePipeFd = wakeFds[1];
    // 设置为非阻塞
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);

    eventItem.data.u32 = EPOLL_ID_WAKE;
    // 添加到epoll的兴趣列表中
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);

    int major, minor;
    getLinuxRelease(&major, &minor);
    // EPOLLWAKEUP was introduced in kernel 3.5
    mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}

在前面进行了一系列的变量的初始化;
然后epoll_create创建了一个epoll对象,可以看到和Handler中一样,IMS中也用到了epoll机制进行监听;
而后可以看到IMS是INotify机制和Epoll机制同时使用的:inotify_init创建iNotify对象,inotify_add_watch则将”/dev/input”路径添加到监听列表中;当”/dev/input”中文件发生变化,将会产生响应;
了解INotifiy文件系统监听机制:
《inotify – Linux 2.6 内核中的文件系统变化通知机制》
《Inotify: 高效、实时的Linux文件系统事件监控框架》
然后将iNotify对象添加到Epoll的兴趣列表中,进行监听;
然后同Handler机制,创建一个Pipe,然后设置为非阻塞形式,然后添加到epoll的兴趣列表中;下面就注意在何时调用epoll_wait来开启监听即可;这里仅进行了初始化;

(二)InputManager:

1)构造函数:
/** \frameworks\native\services\inputflinger\InputManager.cpp **/
class InputManagerInterface : public virtual RefBase {
private:
    sp<InputReaderInterface> mReader;
    sp<InputReaderThread> mReaderThread;

    sp<InputDispatcherInterface> mDispatcher;
    sp<InputDispatcherThread> mDispatcherThread;

    // 构造函数
    InputManager::InputManager(
            const sp<EventHubInterface>& eventHub,
            const sp<InputReaderPolicyInterface>& readerPolicy,
            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
        // 创建InputDispatcher
        mDispatcher = new InputDispatcher(dispatcherPolicy);
        // 创建InputReader
        mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
        initialize();
    }

    /*** 进行初始化 **/
    void InputManager::initialize() {
        // 创建两个Thread的实例
        mReaderThread = new InputReaderThread(mReader);
        mDispatcherThread = new InputDispatcherThread(mDispatcher);
    }

};

InputManager中传入了前面创建的EventHub对象;然后初始化了两个中重要的类,InputDispatcher,以及InputReader;
显然从名字可以看出 InputReader用来读取EventHub中的事件,然后通过InputDiapatcher进行分发(InputReader中持有InputDisptcher的引用);

先看InputDispatcher:

1.1)InputDispatcher:

继承关系:

class InputDispatcher : public InputDispatcherInterface
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface

构造函数:

/** \frameworks\native\services\inputflinger\InputDispatcher.cpp **/
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
    mPolicy(policy),
    mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
    mNextUnblockedEvent(NULL),
    mDispatchEnabled(false), mDispatchFrozen(
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值