Android Input子系统核心服务

作者: lbtrace | 来源:发表于2018-05-14 22:15 被阅读95次

    基于Android 7.0源码分析

    核心服务的类图

    • InputManagerService
      • 负责管理Android输入子系统
      • 封装C++层的InputManager并提供回调
    • NativeInputManager
      • InputManagerService的JNI实现
      • InputManagerService与C++层的InputManager之间的桥梁
    • InputManager
      • Android系统输入事件处理的核心
    • InputReader
      • 包含一些列InputMapper
    • InputReaderThread
      • "InputReader"线程负责读取、预处理原始输入事件以及发送事件到由"InputDispatcherThread"线程管理队列中
    • InputDispatcher
    • InputDispatcherThread
      • "InputDispatcher"线程负责将新的事件异步的发送给应用
    • EventHub
      • 从系统的输入设备获取事件,管理输入设备

    核心服务的创建

    下面从InputManagerService的创建开始分析

        ......
        // 添加Systrace以及system log
        traceBeginAndSlog("StartInputManagerService");
        // context为systemserver的上下文
        inputManager = new InputManagerService(context);
        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        ......
    

    下面看InputManagerService的构造函数

        public InputManagerService(Context context) {
            this.mContext = context;
            // 创建InputManagerHandler用于与"android.display"线程通信
            this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
    
            mUseDevInputEventForAudioJack =
                    context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
            Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                    + mUseDevInputEventForAudioJack);
            // 创建NativeInputManager
            mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    
            // 添加LocalService到LocalServices,用于SystemServer内部通信
            LocalServices.addService(InputManagerInternal.class, new LocalService());
        }
    

    下面看nativeInit

    static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
            jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
        // 这里messageQueue为"android.display"线程的消息队列
        sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
        if (messageQueue == NULL) {
            jniThrowRuntimeException(env, "MessageQueue is not initialized.");
            return 0;
        }
    
        // 创建NativeInputManager
        NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
                messageQueue->getLooper());
        im->incStrong(0);
        return reinterpret_cast<jlong>(im);
    }
    

    下面看NativeInputManager的创建

    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;
        }
        mInteractive = true;
    
        // 创建EventHub
        sp<EventHub> eventHub = new EventHub();
        // 创建InputManager
        mInputManager = new InputManager(eventHub, this, this);
    }
    

    首先看EventHub的构造函数,然后看InputManager的创建

    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);
        LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);
    
        // 创建通知事件队列
        mINotifyFd = inotify_init();
        // 创建观察者监视DEVICE_PATH(/dev/input)下的设备文件的创建与删除
        int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
        LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",
                DEVICE_PATH, errno);
    
        struct epoll_event eventItem;
        memset(&eventItem, 0, sizeof(eventItem));
        eventItem.events = EPOLLIN;
        eventItem.data.u32 = EPOLL_ID_INOTIFY;
        // 监听mINotifyFd
        result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
        LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);
    
        int wakeFds[2];
        // 创建pipe用于主动唤醒EventHub
        result = pipe(wakeFds);
        LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
    
        mWakeReadPipeFd = wakeFds[0];
        mWakeWritePipeFd = wakeFds[1];
    
        result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
        LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
                errno);
    
        result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
        LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
                errno);
    
        eventItem.data.u32 = EPOLL_ID_WAKE;
        // 监听mWakeReadPipeFd
        result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
        LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
                errno);
    
        int major, minor;
        getLinuxRelease(&major, &minor);
        // EPOLLWAKEUP was introduced in kernel 3.5
        mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
    }
    

    至此,EventHub还没有监听特定的输入设备文件描述符。下面看InputManager的创建

    InputManager::InputManager(
            const sp<EventHubInterface>& eventHub,
            const sp<InputReaderPolicyInterface>& readerPolicy,
            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
        // 创建InputDispatcher,dispatcherPolicy引用NativeInputManager
        mDispatcher = new InputDispatcher(dispatcherPolicy);
        // 创建InputReader, readerPolicy引用NativeInputManager
        mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
        // 创建InputDispatcherThread以及InputReaderThread
        initialize();
    }
    

    小结

    • 策略模式
    • 代理模式

    核心服务的启动

    下面从InputManagerServicestart()开始分析

        ......
        // wm.getInputMonitor()返回InputMonitor对象
        inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
        // 调用InputManagerService的start方法
        inputManager.start();
        ......
    
        public void start() {
            Slog.i(TAG, "Starting input manager");
            // 调用nativeStart,mPtr为NativeInputManager对象的地址
            nativeStart(mPtr);
    
            // Add ourself to the Watchdog monitors.
            Watchdog.getInstance().addMonitor(this);
    
            // 监听Setting数据库的改变
            registerPointerSpeedSettingObserver();
            registerShowTouchesSettingObserver();
            registerAccessibilityLargePointerSettingObserver();
            // 注册广播接收机,接收用户切换广播
            mContext.registerReceiver(new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    updatePointerSpeedFromSettings();
                    updateShowTouchesFromSettings();
                    updateAccessibilityLargePointerFromSettings();
                }
            }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
            // 获取Setting数据库信息
            updatePointerSpeedFromSettings();
            updateShowTouchesFromSettings();
            updateAccessibilityLargePointerFromSettings();
        }
    

    下面看NativeStart()的实现

    static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
        NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
    
        // 调用InputManager的start方法
        status_t result = im->getInputManager()->start();
        if (result) {
            jniThrowRuntimeException(env, "Input manager could not be started.");
        }
    }
    

    下面看InputManagerstart()实现

    status_t InputManager::start() {
        // 启动InputDispatcher线程
        status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
        if (result) {
            ALOGE("Could not start InputDispatcher thread due to error %d.", result);
            return result;
        }
        // 启动InputReader线程
        result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
        if (result) {
            ALOGE("Could not start InputReader thread due to error %d.", result);
    
            mDispatcherThread->requestExit();
            return result;
        }
    
        return OK;
    }
    

    至此,EventHub还不能接收输入事件,当InputReader线程启动后会请求EventHub扫描、添加输入设备,下面分析InputReader启动后,EventHub扫描、添加输入设备的过程。
    我们从InputReaderThreadthreadLoop()开始分析。

    bool InputReaderThread::threadLoop() {
        // 调用InputReader的loopOnce()
        mReader->loopOnce();
        // 返回值为true,循环调用
        return true;
    }
    

    下面看InputReaderloopOnce()实现

    void InputReader::loopOnce() {
        int32_t oldGeneration;
        int32_t timeoutMillis;
        bool inputDevicesChanged = false;
        ......
        // 读取输入事件,返回读取的事件数
        size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
        { // acquire lock
            AutoMutex _l(mLock);
            mReaderIsAliveCondition.broadcast();
    
            if (count) {
                // 处理输入事件
                processEventsLocked(mEventBuffer, count);
            }
            ......
        }
        ......
        // 通知InputDispatcherThread分发事件
        mQueuedListener->flush();
    }
    

    下面首先分析EventHubgetEvents()方法,然后看InputReaderprocessEventsLocked方法。

    size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
        ALOG_ASSERT(bufferSize >= 1);
    
        AutoMutex _l(mLock);
    
        struct input_event readBuffer[bufferSize];
    
        RawEvent* event = buffer;
        size_t capacity = bufferSize;
        bool awoken = false;
        for (;;) {
            ......
            // 首次进入mNeedToScanDevices为true,扫描设备
            if (mNeedToScanDevices) {
                mNeedToScanDevices = false;
                scanDevicesLocked();
                mNeedToSendFinishedDeviceScan = true;
            }
            // 构造设备添加事件,mOpeningDevices指向设备链表头
            while (mOpeningDevices != NULL) {
                Device* device = mOpeningDevices;
                ALOGV("Reporting device opened: id=%d, name=%s\n",
                     device->id, device->path.string());
                mOpeningDevices = device->next;
                event->when = now;
                event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
                event->type = DEVICE_ADDED;
                event += 1;
                mNeedToSendFinishedDeviceScan = true;
                if (--capacity == 0) {
                    break;
                }
            }
            // 添加设备扫描完成事件
            if (mNeedToSendFinishedDeviceScan) {
                mNeedToSendFinishedDeviceScan = false;
                event->when = now;
                event->type = FINISHED_DEVICE_SCAN;
                event += 1;
                if (--capacity == 0) {
                    break;
                }
            }
            ......
            // 有事件立即返回
            if (event != buffer || awoken) {
                break;
            }
            ......
        }
    
        // All done, return the number of events we read.
        return event - buffer;
    }
    

    下面看scanDevicesLocked()的实现

    void EventHub::scanDevicesLocked() {
        // 扫描/dev/input下的输入设备
        status_t res = scanDirLocked(DEVICE_PATH);
        if(res < 0) {
            ALOGE("scan dir failed for %s\n", DEVICE_PATH);
        }
        // 创建虚拟按键设备
        if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
            createVirtualKeyboardLocked();
        }
    }
    

    下面看scanDirLocked()的实现

    status_t EventHub::scanDirLocked(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++ = '/';
        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);
            openDeviceLocked(devname);
        }
        closedir(dir);
        return 0;
    }
    

    scanDirLocked()的实现相对简单,扫描/dev/input目录下的设备文件,并打开合法的文件。下面看openDeviceLocked()的实现。

    status_t EventHub::openDeviceLocked(const char *devicePath) {
        char buffer[80];
    
        ALOGV("Opening device: %s", devicePath);
        // 打开设备
        int fd = open(devicePath, O_RDWR | O_CLOEXEC);
        ......
        // Get device name.
        // 获取设备名
        if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
            //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
        } else {
            buffer[sizeof(buffer) - 1] = '\0';
            identifier.name.setTo(buffer);
        }
        ......
        // Check to see if the device is on our excluded list
        // 检查设备是否在排除列表中
        for (size_t i = 0; i < mExcludedDevices.size(); i++) {
            const String8& item = mExcludedDevices.itemAt(i);
            if (identifier.name == item) {
                ALOGI("ignoring event id %s driver %s\n", devicePath, item.string());
                close(fd);
                return -1;
            }
        }
        ......
        // 创建设备对象分配设备id
        // Allocate device.  (The device object takes ownership of the fd at this point.)
        int32_t deviceId = mNextDeviceId++;
        Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
        ......
        // Load the configuration file for the device.
        // 加载设备配置文件(*.idc)
        loadConfigurationLocked(device);
        // Figure out the kinds of events the device reports.
        // 设置输入设备驱动上报的事件类型
        // EV_KEY 按键事件,EV_ABS 绝对坐标,如Touch事件
        ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
        ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
        ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
        ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
        ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
        ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
        ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
        ......
        // Register with epoll.
        struct epoll_event eventItem;
        memset(&eventItem, 0, sizeof(eventItem));
        eventItem.events = EPOLLIN;
        if (mUsingEpollWakeup) {
            eventItem.events |= EPOLLWAKEUP;
        }
        eventItem.data.u32 = deviceId;
        // 设备文件描述符添加到EventHub的epoll
        if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
            ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
            delete device;
            return -1;
        }
        ......
        // 设备添加到EventHub的mDevices中
        addDeviceLocked(device);
        return 0;
    }
    

    EventHub扫描完输入设备后,产生一系列设备添加事件,下面看InputReader处理设备添加事件。回到InputReaderloopOnce()中看processEventsLocked的实现。

    void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
        for (const RawEvent* rawEvent = rawEvents; count;) {
            int32_t type = rawEvent->type;
            size_t batchSize = 1;
            // 普通的输入事件,同一设备的事件作为一个batch
            if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
                int32_t deviceId = rawEvent->deviceId;
                while (batchSize < count) {
                    if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
                            || rawEvent[batchSize].deviceId != deviceId) {
                        break;
                    }
                    batchSize += 1;
                }
    #if DEBUG_RAW_EVENTS
                ALOGD("BatchSize: %d Count: %d", batchSize, count);
    #endif
                processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
            } else {
                switch (rawEvent->type) {
                case EventHubInterface::DEVICE_ADDED:
                    // 处理设备添加
                    addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::DEVICE_REMOVED:
                    removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                    break;
                case EventHubInterface::FINISHED_DEVICE_SCAN:
                    // 处理设备扫描完成
                    handleConfigurationChangedLocked(rawEvent->when);
                    break;
                default:
                    ALOG_ASSERT(false); // can't happen
                    break;
                }
            }
            count -= batchSize;
            rawEvent += batchSize;
        }
    }
    

    下面重点看设备添加事件处理函数addDeviceLocked()的实现

    void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
        ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
        if (deviceIndex >= 0) {
            ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
            return;
        }
        // 从EventHub获取设备信息
        InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
        uint32_t classes = mEventHub->getDeviceClasses(deviceId);
        int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
    
        // 创建输入设备并添加相应的InputMapper
        InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
        device->configure(when, &mConfig, 0);
        device->reset(when);
    
        if (device->isIgnored()) {
            ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
                    identifier.name.string());
        } else {
            ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
                    identifier.name.string(), device->getSources());
        }
        // 添加到mDevices中
        mDevices.add(deviceId, device);
        bumpGenerationLocked();
        ......
    }
    

    下面看createDeviceLocked()的实现

    InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
            const InputDeviceIdentifier& identifier, uint32_t classes) {
        // 创建InputDevice
        InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
                controllerNumber, identifier, classes);
        ......
        // Keyboard-like devices.
        // 类键盘设备添加InputMapper
        uint32_t keyboardSource = 0;
        // 普通的按键类型
        int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
        if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
            // 普通的按键keyboardSource
            keyboardSource |= AINPUT_SOURCE_KEYBOARD;
        }
        if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
            keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
        }
        if (classes & INPUT_DEVICE_CLASS_DPAD) {
            keyboardSource |= AINPUT_SOURCE_DPAD;
        }
        if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
            keyboardSource |= AINPUT_SOURCE_GAMEPAD;
        }
    
        if (keyboardSource != 0) {
            device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
        }
    
        // Cursor-like devices.
        // 类Cursor(鼠标或者traceball)设备添加InputMapper
        if (classes & INPUT_DEVICE_CLASS_CURSOR) {
            device->addMapper(new CursorInputMapper(device));
        }
    
        // Touchscreens and touchpad devices.
        // 触摸屏、触控板设备添加InputMapper
        if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
            // 通常为MultiTouch
            device->addMapper(new MultiTouchInputMapper(device));
        } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
            device->addMapper(new SingleTouchInputMapper(device));
        }
        ......
    }
    

    InputMapper负责加工原始的输入事件,一个输入设备可以关联多个InputMapper,这样可以处理不同类型的事件。

    至此,Input核心服务启动完成,接下来EventHub就可以监听驱动上报的输入事件了。

    相关文章

      网友评论

        本文标题:Android Input子系统核心服务

        本文链接:https://www.haomeiwen.com/subject/uirsdftx.html