Android板级支持与硬件相关子系统
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

5.3 Android4.2的用户输入子系统结构

↘5.3.1 总体结构

Android4.2的输入系统的结构产生了一些变化,这些变化让输入公共部分和应用程序的输入部分的分工更加明确。

Android4.2输入系统的结构如图5-2所示。

图5-2 Android4.2输入系统的结构

libinput是新引入的一个库,代码路径为:frameworks/base/services/input/,其中的内容将生成libinput.so,作为输入系统中底层最相关的一部分,EventHub是其中的一部分,用于调用Event输入设备。

libinput被InputManagerService的JNI所调用:

·frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp InputManagerService运行于系统服务器进程,调用底层并提供全局输入管理:

·frameworks/base/services/java/com/android/server/input/InputManagerService.java

libandroidfw也是新引入的一个库,含义为Android的框架库(Framework),它完成按键布局方面的处理。按键相关的内容由从前版本的UI库移到此处。

经过JNI的封装后,提供KeyEnvent和MotionEvent两个类的支持,这部分内容运行于应用程序的进程中。

提示:Android 4.0就引入了libinput库,但没有InputManagerService。

↘5.3.2 InputManagerService的实现

在Android4.x中InputManagerService是输入系统的核心环节,它本身在系统服务器当中,包名为com.android.server.input。InputManagerService是集合输入系统所有功能的一个类,而从前的版本则由InputManager等几个类完成对应功能。

InputManagerService当中的底层功能交由本地处理,其中的几个方法如下所示:

        private static native int nativeInit(InputManagerService service,
                Context context, MessageQueue messageQueue);   // 初始化
        private static native void nativeStart(int ptr);       // 开始
        private static native int nativeGetScanCodeState(int ptr,  // 获得扫描码状态
                              int deviceId, int sourceMask, int scanCode);
        private static native int nativeGetKeyCodeState(int ptr,   // 获得按键码状态
                              int deviceId, int sourceMask, int keyCode);

几个notifyXXX()函数用于通知,这些函数也可以被本地的代码调用,充当回调的功能。其中的一个notifyInputDevicesChanged()函数如下所示:

        private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
            synchronized (mInputDevicesLock) {
                if (!mInputDevicesChangedPending) {
                    mInputDevicesChangedPending = true;
                    mHandler.obtainMessage(MSG_DELIVER_INPUT_DEVICES_CHANGED,
                                        mInputDevices).sendToTarget();     // 分发的消息
                }
                mInputDevices = inputDevices;                              // 赋值新的设备
            }
        }

调用Handler发送消息的过程,也就是交由InputManagerService进行处理。一个细节是要首先向挂起设备发送,然后将参数中传入的InputDevice数组赋值给mInputDevices。

本地代码在com_android_server_input_InputManagerService.cpp文件中,其中包括大量的JNI实现,获得按键码状态的函数如下所示:

    static jint nativeGetKeyCodeState(JNIEnv* env, jclass clazz,
            jint ptr, jint deviceId, jint sourceMask, jint keyCode) {
        NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
        return im->getInputManager()->getReader()->getKeyCodeState(
                deviceId, uint32_t(sourceMask), keyCode);
    }

用于通知notifyInputDevicesChanged()的函数如下所示:

    void NativeInputManager::notifyInputDevicesChanged(
                                  const Vector<InputDeviceInfo>& inputDevices) {
        JNIEnv* env = jniEnv();
        size_t count = inputDevices.size();
        jobjectArray inputDevicesObjArray = env->NewObjectArray(count,
                            gInputDeviceClassInfo.clazz, NULL); // 得到设备数组
        if (inputDevicesObjArray) {
            bool error = false;
            for (size_t i = 0; i < count; i++) {       // 对设备循环进行处理
                jobject inputDeviceObj =
                    android_view_InputDevice_create(env, inputDevices.itemAt(i));
    //省略错误处理的内容
                env->SetObjectArrayElement(inputDevicesObjArray, i, inputDeviceObj);
                env->DeleteLocalRef(inputDeviceObj);
            }
            if (!error) {
                env->CallVoidMethod(mServiceObj,       // 调用Java的方法
                gServiceClassInfo.notifyInputDevicesChanged, inputDevicesObjArray);
            }
            env->DeleteLocalRef(inputDevicesObjArray);
        }
        checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged");
    }

代码中包括多设备的处理,使用一个循环遍历找到所有的设备。