1) 按键处理主要的功臣是WindowManagerService. mInputManager
@WindowManagerService.java
mInputManager = new InputManager(context, this);
@InputManager.java
public InputManager(Context context, WindowManagerService windowManagerService) {
this.mContext = context;
this.mWindowManagerService = windowManagerService;
this.mCallbacks = new Callbacks();
Looper looper = windowManagerService.mH.getLooper();
Slog.i(TAG, "Initializing input manager");
nativeInit(mContext, mCallbacks, looper.getQueue());
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}
@com_android_server_InputManager.cpp
static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
jobject contextObj, jobject callbacksObj, jobject messageQueueObj) {
if (gNativeInputManager == NULL) {
sp<Looper> looper = android_os_MessageQueue_getLooper(env, messageQueueObj);
gNativeInputManager = new NativeInputManager(contextObj, callbacksObj, looper);
} else {
LOGE("Input manager already initialized.");
jniThrowRuntimeException(env, "Input manager already initialized.");
}
}
NativeInputManager::NativeInputManager(jobject contextObj,
jobject callbacksObj, const sp<Looper>& looper) :
mLooper(looper) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
mCallbacksObj = env->NewGlobalRef(callbacksObj);
{
AutoMutex _l(mLock);
mLocked.displayWidth = -1;
mLocked.displayHeight = -1;
mLocked.displayExternalWidth = -1;
mLocked.displayExternalHeight = -1;
mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
}
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
@inputManager.cpp
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
2) 接下来,重点来了,inputDispatcher负责事件(key、touch)的分发,而事件处理延时的ANR也在它这里。InputReader主要负责读取底层传上来的事件,这里就不介绍了。
@inputDispatcher.cpp
// If the currently focused window is still working on previous events then keep waiting.
if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindowHandle)) {
#if DEBUG_FOCUS
LOGD("Waiting because focused window still processing previous input.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime);
goto Unresponsive;
}
...
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
const EventEntry* entry,
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime) {
...
if (currentTime >= mInputTargetWaitTimeoutTime) {
onANRLocked(currentTime, applicationHandle, windowHandle,
entry->eventTime, mInputTargetWaitStartTime);
// Force poll loop to wake up immediately on next iteration once we get the
// ANR response back from the policy.
*nextWakeupTime = LONG_LONG_MIN;
return INPUT_EVENT_INJECTION_PENDING;
} else {
// Force poll loop to wake up when timeout is due.
if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {
*nextWakeupTime = mInputTargetWaitTimeoutTime;
}
return INPUT_EVENT_INJECTION_PENDING;
}
}
void InputDispatcher::onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
nsecs_t eventTime, nsecs_t waitStartTime) {
LOGI("Application is not responding: %s. "
"%01.1fms since event, %01.1fms since wait started",
getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
(currentTime - eventTime) / 1000000.0,
(currentTime - waitStartTime) / 1000000.0);
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
commandEntry->inputWindowHandle = windowHandle;
}
void InputDispatcher::doNotifyANRLockedInterruptible(
CommandEntry* commandEntry) {
mLock.unlock();
nsecs_t newTimeout = mPolicy->notifyANR(
commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle);
mLock.lock();
resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
commandEntry->inputWindowHandle != NULL
? commandEntry->inputWindowHandle->getInputChannel() : NULL);
}
这里的mPlicy是在构造的时候初始化的。追溯前面的inputManager.cpp,com_android_server_InputManager.cpp,很快
发现mPlicy其实就是NativeInputManager。
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
@ com_android_server_InputManager.cpp
nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputWindowHandle>& inputWindowHandle) {
#if DEBUG_INPUT_DISPATCHER_POLICY
LOGD("notifyANR");
#endif
JNIEnv* env = jniEnv();
jobject inputApplicationHandleObj =
getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
jobject inputWindowHandleObj =
getInputWindowHandleObjLocalRef(env, inputWindowHandle);
jlong newTimeout = env->CallLongMethod(mCallbacksObj,
gCallbacksClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj);
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
newTimeout = 0; // abort dispatch
} else {
assert(newTimeout >= 0);
}
env->DeleteLocalRef(inputWindowHandleObj);
env->DeleteLocalRef(inputApplicationHandleObj);
return newTimeout;
}
3) 仔细回忆下前面从java层到native层的inputManger和inputDispatcher的构造,不难发现mPlicy的notifyANR()最终回到inputManager.java中对应Callbacks的notifyANR()。(JNI:不仅java层访问本地方法,同样在本地方法中也可以访问java层方法)
@inputManager.java
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle) {
return mWindowManagerService.mInputMonitor.notifyANR(
inputApplicationHandle, inputWindowHandle);
}
@WindowManagerService.java
final InputMonitor mInputMonitor = new InputMonitor(this);
@InputMonitor.java
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle) {
AppWindowToken appWindowToken = null;
if (inputWindowHandle != null) {
synchronized (mService.mWindowMap) {
WindowState windowState = (WindowState) inputWindowHandle.windowState;
if (windowState != null) {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out sending to "
+ windowState.mAttrs.getTitle());
appWindowToken = windowState.mAppToken;
}
}
}
if (appWindowToken == null && inputApplicationHandle != null) {
appWindowToken = inputApplicationHandle.appWindowToken;
if (appWindowToken != null) {
Slog.i(WindowManagerService.TAG,
"Input event dispatching timed out sending to application "
+ appWindowToken.stringName);
}
}
if (appWindowToken != null && appWindowToken.appToken != null) {
try {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
boolean abort = appWindowToken.appToken.keyDispatchingTimedOut();
if (! abort) {
// The activity manager declined to abort dispatching.
// Wait a bit longer and timeout again later.
return appWindowToken.inputDispatchingTimeoutNanos;
}
} catch (RemoteException ex) {
}
}
return 0; // abort dispatching
}
class AppWindowToken extends WindowToken {
// Non-null only for application tokens.
final IApplicationToken appToken;
其实这里的appToken实质上是一个ActivityRecord的“代理”。(需了解binder)
@ActivityRecord.java
final class ActivityRecord {
final ActivityManagerService service; // owner
final ActivityStack stack; // owner
final IApplicationToken.Stub appToken; // window manager token
public boolean keyDispatchingTimedOut() {
ActivityRecord r;
ProcessRecord anrApp = null;
synchronized(service) {
r = getWaitingHistoryRecordLocked();
if (r != null && r.app != null) {
if (r.app.debugging) {
return false;
}
if (service.mDidDexOpt) {
// Give more time since we were dexopting.
service.mDidDexOpt = false;
return false;
}
if (r.app.instrumentationClass == null) {
anrApp = r.app;
} else {
Bundle info = new Bundle();
info.putString("shortMsg", "keyDispatchingTimedOut");
info.putString("longMsg", "Timed out while dispatching key event");
service.finishInstrumentationLocked(
r.app, Activity.RESULT_CANCELED, info);
}
}
}
if (anrApp != null) {
service.appNotResponding(anrApp, r, this,
"keyDispatchingTimedOut");
}
return true;
}
接下去就是ActivityManagerService的appNotResponding,我们平常所看到的ANR对话框正出自这里。