前言
在看这篇文章之前我们可以带着以下几个问题来看:
- input的分发流程是怎样的?
- input事件是通过什么方式把事件传递到应用进程?
- ims里面是怎么去找到当前的焦点app以及window?
- ims里面ANR超时5s是在哪里定义的?
-
ims里面ANR的发生是怎么去处理的?
- WindowInputEventReceiver中的onInputEvent方法,是运行在主线程还是子线程?
可以先看初始化流程,了解IMS的由来,如果对IMS有一定了解,上述问题可以直接看专栏里面的后续文章。
IMS启动流程:
input事件分发流程:
IMS问题复盘:
1. IMS初始化流程
IMS属于系统重要服务,同样运行在SystemServer进程里面,在系统启动过程中,也会去初始化这些系统服务。
1.1 SystemServer.startOtherServices
/frameworks/base/services/java/com/android/server/SystemServer.java
ims的初始化入口在SystemServer中的startOtherServices方法里面
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
t.traceBegin("startOtherServices");
.....
InputManagerService inputManager = null;
.....
t.traceBegin("StartInputManagerService");
inputManager = new InputManagerService(context);
t.traceEnd();
.....
t.traceBegin("StartInputManager");
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
inputManager.start();
t.traceEnd();
.......
}
这里会将ims的实例传递给wms,后面WMS与IMS的交互都是通过此实例,在inputManager.start之前,会将wm中的InputManagerCallback注册到IMS中。
1.2 IMS构造函数
/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mStaticAssociations = loadStaticInputPortAssociations();
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService()); }
IMS的构造函数主要做了如下几件事:
- 初始化InputManagerHandler(InputManagerHandler处理input相关的UI变化信息,例如keyboard与native状态发生变化时进行callback通知到wms)。
- 调用nativeInit函数返回mPtr,是IMS和native交互的关键,这个是NativeInputManager的指针。
- 将IMS加入到LocalServices里面。
1.3 com_android_server_input_InputManagerService.nativeInit
/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == nullptr) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
初始化NativeInputManager。
1.4 com_android_server_input_InputManagerService.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();
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
mLocked.pointerCapture = false;
mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
}
mInteractive = true;
mInputManager = new InputManager(this, this);
defaultServiceManager()->addService(String16("inputflinger"),
mInputManager, false);
}
初始化InputManager。
NativeInputManager是java和native的桥梁,从类的声明来看NativeInputManager包含了InputReader和InputDispatcher的回调interface.后面从dispatcher和reader抛出来的notify都是在这里转换后抛给java。
defaultServiceManager()->addService作用往ServiceManager中添加了一个inputflinger服务,用来管理IMS的inputChannel的register和unregister。
1.5 InputManager构造函数
/frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
mReader = createInputReader(readerPolicy, mClassifier);
}
创建InputDispatcher。
初始化InputClassifier,这里InputClassifier的作用是InputReader与InputDispatcher通信是通过媒介InputClassifier实例进行,构造InputClassifier时将InputDispatcher作为参数传入。
创建InputReader。
1.6 InputDispatcher构造函数
/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
: mPolicy(policy),
mPendingEvent(nullptr),
mLastDropReason(DropReason::NOT_DROPPED),
mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
mAppSwitchSawKeyDown(false),
mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(nullptr),
mDispatchEnabled(false),
mDispatchFrozen(false),
mInputFilterEnabled(false),
// mInTouchMode will be initialized by the WindowManager to the default device config.
// To avoid leaking stack in case that call never comes, and for tests,
// initialize it here anyways.
mInTouchMode(true),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT) {
mLooper = new Looper(false);
mReporter = createInputReporter();
mKeyRepeatState.lastKeyEntry = nullptr;
policy->getDispatcherConfiguration(&mConfig);
}
创建属于InputDispatcher的looper,从这里可以大致看出InputDispatcher的实现模型就是looper的机制,只不过Input并没有使用Looper相关的Message相关的功能,也就是说没有MessageQueue了,仅是单纯的使用Looper的addFd功能,以及它的epoll阻塞唤醒功能。
1.7 InputReader构造函数
/frameworks/native/services/inputflinger/reader/InputReader.cpp
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener)
: mContext(this),
mEventHub(eventHub),
mPolicy(policy),
mGlobalMetaState(0),
mGeneration(1),
mNextInputDeviceId(END_RESERVED_ID),
mDisableVirtualKeysTimeout(LLONG_MIN),
mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
这里主要是将主要是将EventHub保存成私有成员,保存NativeInputManager注册在InputReader中的callback中,通过与InputDispatcher的媒介InputClassifier创建QueuedInputListener,这个主要目的是notify,不过是把多个notify暂时存放成队列,最后通过函数flush()在分别通知出去,所以类名中有个queue。
1.8 EventHub构造函数
/frameworks/native/services/inputflinger/reader/EventHub.cpp
EventHub::EventHub(void)
: mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
mNextDeviceId(1),
mControllerNumbers(),
mOpeningDevices(nullptr),
mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false),
mNeedToScanDevices(true),
mPendingEventCount(0),
mPendingEventIndex(0),
mPendingINotify(false) {
ensureProcessCanBlockSuspend();
//创建epoll对象
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
//创建inotify对象
mINotifyFd = inotify_init();
mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
strerror(errno));
if (isV4lScanningEnabled()) {
mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
VIDEO_DEVICE_PATH, strerror(errno));
} else {
mVideoWd = -1;
ALOGI("Video device scanning disabled");
}
//将mINotifyFd作为mEpollFd的一个监控对象
struct epoll_event eventItem = {};
eventItem.events = EPOLLIN | EPOLLWAKEUP;
eventItem.data.fd = mINotifyFd;
int 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);
//创建唤醒pipe,EventHub唤醒时(wake()),往writepipe写值,readpipe受mEpollFd监控
int wakeFds[2];
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.fd = 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);
}
主要作用就是通过inotify监听 /dev/input里的文件的变化,另外创建了一个管道, 将read fd加入到epoll中去监听,而write fd主要用来唤醒epoll。
1.9 IMS初始化流程总结
- 创建NativeInputManager实例,作为后面native和java之间的传送点。
- 创建InputDispatcher实例,并将NativeInputManager作为callback传入InputDispatcher中。
- 创建InputReader实例,并将NativeInputManager作为callback传入InputReader中。
- 创建InputClassifier实例,将其作为InputReader与InputDispatcher通信的媒介。
- 创建EventHub实例,并保存在InputReader中,后期input的event获取都通过EventHub获取。