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"); }
代码中包括多设备的处理,使用一个循环遍历找到所有的设备。