开局叠甲,可能理解有误,请大佬们斧正。
- Android Framework-Input-1 基础梳理
- Android Framework-Input-2 构建和启动
- Android Framework-Input-3 数据处理
- Android Framework-Input-4 IQ到OQ
- Android Framework-Input-5 分发事件
- Android Framework-Input-6 事件分发到View
- Android Framework-Input-7 事件的移除
其实Input
相关的ANR
一边表现为咱们常说的卡住,然后等待一段时间,熟悉的ANR弹窗就出来了。
我们看下Input
相关ANR
的原因。
C++
//native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchOnce() {
//省略
//如果没有commands 则进行事件分发
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
if (runCommandsLockedInterruptible()) { // 执行commands
nextWakeupTime = LONG_LONG_MIN; // 立即进行下一轮的派发
}
const nsecs_t nextAnrCheck = processAnrsLocked();
//获取最小的唤醒时间
nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
if (nextWakeupTime == LONG_LONG_MAX) {
mDispatcherEnteredIdle.notify_all();
}
//省略
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
在processAnrsLocked
方法里, 如果有在等待出现焦点窗口的操作,判断是否有超时,如果出现超时,则会调用 onAnrLocked
, 通知出现ANR
。 对所有的connection
检查是否有ANR
出现,出现则调用onAnrLocked
通知出现ANR
。 简单来说,一种是连着,WQ
里炸弹没移除掉。第二种,找不到要给焦点的对象(Window
)。
c++
nsecs_t InputDispatcher::processAnrsLocked() {
const nsecs_t currentTime = now();
nsecs_t nextAnrCheck = LONG_LONG_MAX;
// // 等待焦点应用的focused 窗口出现 mNoFocusedWindowTimeoutTime 会在 findFocusedWindowTargetsLocked 里赋值 也就是一个超时时间
if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {
if (currentTime >= *mNoFocusedWindowTimeoutTime) {//场景1: 触发noFocusedWindow的anr
processNoFocusedWindowAnrLocked();// 1.1
mAwaitedFocusedApplication.reset();//重置
mNoFocusedWindowTimeoutTime = std::nullopt;
return LONG_LONG_MIN;//直接返回最小值 下一个判断
} else {
nextAnrCheck = *mNoFocusedWindowTimeoutTime;//下次的时间
}
}
// 检查是否有任何连接 ANR 到期,mAnrTracker 中保存所有已分发事件(未被确认消费的事件)的超时时间
nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout());
if (currentTime < nextAnrCheck) { //一切正常,在 nextAnrCheck 再检查一次
return nextAnrCheck;
}
// 如果我们到达这里,则连接无响应。
sp<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());
if (connection == nullptr) {
return nextAnrCheck;
}
connection->responsive = false;//没响应了
// 停止为此无响应的连接唤醒
mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());// // 移除此token对应的记录
// 场景2: 触发ANR 1.2
onAnrLocked(connection);// 通知ANR发生, 注意此处的参数是 Connection
return LONG_LONG_MIN;//立即进行下一轮循环
}
- onAnrLocked(app)
c
//找不到focus的window,但是找到当前获取input事件的应用。
void InputDispatcher::onAnrLocked(std::shared_ptr<InputApplicationHandle> application) {
std::string reason =
StringPrintf("%s does not have a focused window", application->getName().c_str());
//收集anr的window、reason信息
updateLastAnrStateLocked(*application, reason);
std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
&InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible);
commandEntry->inputApplicationHandle = std::move(application);
//将anr的命令添加到 mCommandQueue 中 回调 doNotifyNoFocusedWindowAnrLockedInterruptible
postCommandLocked(std::move(commandEntry));
}
//会调用 doNotifyNoFocusedWindowAnrLockedInterruptible
void InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) {
mLock.unlock();
mPolicy->notifyNoFocusedWindowAnr(commandEntry->inputApplicationHandle);
mLock.lock();
}
- onAnrLocked(connection)
c
void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
//如果消息等待队列是null 那就不用检查了 没等待消息怎么anr
if (connection->waitQueue.empty()) {
return;
}
DispatchEntry* oldestEntry = *connection->waitQueue.begin();
//计算当前超时时间
const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
//构建弹出消息体
std::string reason =
android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
connection->inputChannel->getName().c_str(),
ns2ms(currentWait),
oldestEntry->eventEntry->getDescription().c_str());
sp<IBinder> connectionToken = connection->inputChannel->getConnectionToken();
// 记录ANR信息
updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason);
processConnectionUnresponsiveLocked(*connection, std::move(reason));
cancelEventsForAnrLocked(connection);
}
void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection,
std::string reason) {
const sp<IBinder>& connectionToken = connection.inputChannel->getConnectionToken();
if (connection.monitor) {
std::optional<int32_t> pid = findMonitorPidByTokenLocked(connectionToken);
if (!pid.has_value()) {
return;
}
sendMonitorUnresponsiveCommandLocked(pid.value(), std::move(reason));
return;
}
sendWindowUnresponsiveCommandLocked(connectionToken, std::move(reason));
}
void InputDispatcher::sendWindowUnresponsiveCommandLocked(sp<IBinder> connectionToken,
std::string reason) {
std::unique_ptr<CommandEntry> windowUnresponsiveCommand = std::make_unique<CommandEntry>(
&InputDispatcher::doNotifyWindowUnresponsiveLockedInterruptible);
windowUnresponsiveCommand->connectionToken = std::move(connectionToken);
windowUnresponsiveCommand->reason = std::move(reason);
postCommandLocked(std::move(windowUnresponsiveCommand));
}
//会调用doNotifyWindowUnresponsiveLockedInterruptible
void InputDispatcher::doNotifyWindowUnresponsiveLockedInterruptible(CommandEntry* commandEntry) {
mLock.unlock();
mPolicy->notifyWindowUnresponsive(commandEntry->connectionToken, commandEntry->reason);
mLock.lock();
}
- mPolicy的由来
js
sp<InputDispatcherPolicyInterface> mPolicy;
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
: mPolicy(policy),
而我们在InputManager.cpp
的初始化过程中,
可以看出 其实传入的policy
其实就是 this
,也就说其实会回调到com_android_server_input_InputManagerService
中
c
//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.systemUiLightsOut = false;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
mLocked.pointerCapture = false;
mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
}
mInteractive = true;
InputManager* im = new InputManager(this, this);
mInputManager = im;
defaultServiceManager()->addService(String16("inputflinger"), im);
}
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
mReader = createInputReader(readerPolicy, mClassifier);
}
sp<InputDispatcherInterface> createInputDispatcher(
const sp<InputDispatcherPolicyInterface>& policy) {
return new android::inputdispatcher::InputDispatcher(policy);
}
我们看下JNI对应的方法
c
void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyWindowUnresponsive");
#endif
ATRACE_CALL();
JNIEnv* env = jniEnv();
ScopedLocalFrame localFrame(env);
jobject tokenObj = javaObjectForIBinder(env, token);
ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));
env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowUnresponsive, tokenObj,
reasonObj.get());
checkAndClearExceptionFromCallback(env, "notifyWindowUnresponsive");
}
void NativeInputManager::notifyNoFocusedWindowAnr(
const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
ScopedLocalFrame localFrame(env);
jobject inputApplicationHandleObj =
getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyNoFocusedWindowAnr,
inputApplicationHandleObj);
checkAndClearExceptionFromCallback(env, "notifyNoFocusedWindowAnr");
}
会反向调用到InputManagerService.java
java
//base/services/core/java/com/android/server/input/InputManagerService.java
private void notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle) {
mWindowManagerCallbacks.notifyNoFocusedWindowAnr(inputApplicationHandle);
}
// Native callback
private void notifyWindowUnresponsive(IBinder token, String reason) {
mWindowManagerCallbacks.notifyWindowUnresponsive(token, reason);
}
然后一路回调下去 ,最后调用到
java
com.android.server.am.AppErrors
void handleShowAnrUi(Message msg) {
List<VersionedPackage> packageList = null;
boolean doKill = false;
AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
final ProcessRecord proc = data.proc;
if (proc == null) {
Slog.e(TAG, "handleShowAnrUi: proc is null");
return;
}
synchronized (mProcLock) {
final ProcessErrorStateRecord errState = proc.mErrorState;
if (!proc.isPersistent()) {
packageList = proc.getPackageListWithVersionCode();
}
if (errState.getDialogController().hasAnrDialogs()) {
Slog.e(TAG, "App already has anr dialog: " + proc);
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
AppNotRespondingDialog.ALREADY_SHOWING);
return;
}
boolean showBackground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0,
mService.mUserController.getCurrentUserId()) != 0;
if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) {
AnrController anrController = errState.getDialogController().getAnrController();
if (anrController == null) {
errState.getDialogController().showAnrDialogs(data);
} else {
String packageName = proc.info.packageName;
int uid = proc.info.uid;
boolean showDialog = anrController.onAnrDelayCompleted(packageName, uid);
if (showDialog) {
Slog.d(TAG, "ANR delay completed. Showing ANR dialog for package: "
+ packageName);
errState.getDialogController().showAnrDialogs(data);
} else {
Slog.d(TAG, "ANR delay completed. Cancelling ANR dialog for package: "
+ packageName);
errState.setNotResponding(false);
errState.setNotRespondingReport(null);
errState.getDialogController().clearAnrDialogs();
}
}
} else {
MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
AppNotRespondingDialog.CANT_SHOW);
// Just kill the app if there is no dialog to be shown.
doKill = true;
}
}
if (doKill) {
mService.killAppAtUsersRequest(proc);
}
// Notify PackageWatchdog without the lock held
if (packageList != null) {
mPackageWatchdog.onPackageFailure(packageList,
PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
}
}