背景
來(lái)自于一個(gè)網(wǎng)友在技術(shù)交流群中問(wèn)題,我正好之前開(kāi)發(fā)過(guò)程中也遇到了類(lèi)似的問(wèn)題,寫(xiě)個(gè)文章記錄一下。
InputDispatcher: Untrusted touch due to occlusion by com.xx.xx/10074 (obscuring opacity = 1.00, maximum allowed = 0.80)
InputDispatcher: Dropping untrusted touch event due to com.xx.xx/10074
大佬們,請(qǐng)教個(gè)問(wèn)題哈,測(cè)試時(shí)發(fā)現(xiàn)launcher上有個(gè)app,點(diǎn)擊按鈕沒(méi)反應(yīng),然后撈了下日志,發(fā)現(xiàn)有輸出上述這2行日志。
請(qǐng)問(wèn)下大佬們,這2行日志是干啥的呢?
一、這個(gè)功能到底有什么用
保護(hù)你的手機(jī)操作的安全,避免你誤點(diǎn)了某個(gè)功能,怎么理解這件事?

舉個(gè)例子,假如懸浮窗口B設(shè)置成了可穿透的觸摸模式,就是touch事件可以穿透到應(yīng)用A,那用戶(hù)在不清楚狀況的情況下,以為點(diǎn)擊了紫色的“取消"按鈕,最后生效的是綠色的“付款“”按鈕那不是很危險(xiǎn)嗎?
為了維持系統(tǒng)安全并保持良好的用戶(hù)體驗(yàn),Android 12 會(huì)阻止應(yīng)用使用[觸摸事件],也就是說(shuō)系統(tǒng)會(huì)屏蔽穿透某些窗口的觸摸操作。
圖中就應(yīng)該屏蔽點(diǎn)擊取消的觸摸事件,阻止應(yīng)用A使用這次觸摸事件
二、受影響的應(yīng)用
此變更會(huì)影響選擇讓觸摸操作穿透其窗口的應(yīng)用,例如使用 [FLAG_NOT_TOUCHABLE]標(biāo)志,但不限于以下示例:
- 需要
SYSTEM_ALERT_WINDOW權(quán)限并使用FLAG_NOT_TOUCHABLE標(biāo)志的疊加層,例如使用TYPE_APPLICATION_OVERLAY的窗口。 - 使用
FLAG_NOT_TOUCHABLE標(biāo)志的 activity 窗口。
三、允許被透?jìng)鞯睦馇闆r
3.1 應(yīng)用中的互動(dòng)。您的應(yīng)用會(huì)顯示疊加層,并且只有當(dāng)用戶(hù)與您的應(yīng)用進(jìn)行互動(dòng)時(shí)才會(huì)顯示疊加層。
這個(gè)很好理解,以為都是你app內(nèi)部的事,不用擔(dān)心有什么不安全的,除非app自己想搞事情
3.2 可信窗口。包括但不限于以下窗口:
無(wú)障礙窗口
輸入法 (IME) 窗口
Google 助理窗口
注意:類(lèi)型為 TYPE_APPLICATION_OVERLAY 的窗口不受信任。
這個(gè)也好理解,畢竟都是系統(tǒng)內(nèi)部的窗口
3.3 不可見(jiàn)窗口。窗口的根視圖是 GONE 或 INVISIBLE。
不會(huì)造成用戶(hù)的誤解
3.4 全透明窗口。窗口的 alpha 屬性為 0.0。
與3.3理由一樣
3.5 足夠半透明的系統(tǒng)警報(bào)窗口。當(dāng)組合后的不透明度小于或等于系統(tǒng)針對(duì)觸摸的最大遮掩不透明度時(shí),系統(tǒng)會(huì)將一組系統(tǒng)警報(bào)窗口視為足夠半透明。在 Android 12 中,默認(rèn)最大不透明度為 0.8。
這個(gè)網(wǎng)友遇到的錯(cuò)誤就是obscuring opacity = 1.00, maximum allowed = 0.80,不透明度1.00,怎么能允許被穿透呢,所以這個(gè)應(yīng)用寫(xiě)的就是不符合規(guī)范。
只有讓用戶(hù)可以有足夠的透明度知道自己點(diǎn)擊的是后面那個(gè)窗口,那才是受信任的觸摸。
四、檢測(cè)不受信任的觸摸操作是否被屏蔽
可以通過(guò)adb日志查看
Untrusted touch due to occlusion by PACKAGE_NAME
如需允許不受信任的觸摸操作,請(qǐng)?jiān)诮K端窗口中運(yùn)行以下 ADB 命令
# A specific app
adb shell am compat disable BLOCK_UNTRUSTED_TOUCHES com.example.app
# All apps
# If you'd still like to see a Logcat message warning when a touch would be
# blocked, use 1 instead of 0.
adb shell settings put global block_untrusted_touches 0
如需將行為還原為默認(rèn)設(shè)置(不受信任的觸摸操作被屏蔽),請(qǐng)運(yùn)行以下命令:
# A specific app
adb shell am compat reset BLOCK_UNTRUSTED_TOUCHES com.example.app
# All apps
adb shell settings put global block_untrusted_touches 2
這里注意block_untrusted_touches為2是打開(kāi)功能,1是關(guān)閉這個(gè)功能,但是還有日志輸出,0是徹底關(guān)閉這個(gè)功能,沒(méi)有日志輸出。
五、代碼
具體的代碼實(shí)現(xiàn)在findTouchedWindowTargetsLocked的邏輯中,會(huì)調(diào)用computeTouchOcclusionInfoLocked算出TouchOcclusionInfo,然后再調(diào)用isTouchTrustedLocked確認(rèn)是否是信任的觸摸事件,有興趣的可以看看實(shí)現(xiàn)細(xì)節(jié)。
InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) {
...
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
// Drop events that can't be trusted due to occlusion
if (mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) {
TouchOcclusionInfo occlusionInfo =
computeTouchOcclusionInfoLocked(windowHandle, x, y);
if (!isTouchTrustedLocked(occlusionInfo)) {
if (DEBUG_TOUCH_OCCLUSION) {
ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
for (const auto& log : occlusionInfo.debugInfo) {
ALOGD("%s", log.c_str());
}
}
sendUntrustedTouchCommandLocked(occlusionInfo.obscuringPackage);
if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
ALOGW("Dropping untrusted touch event due to %s/%d",
occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
continue;
}
}
}
}
}
bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const {
if (occlusionInfo.hasBlockingOcclusion) {
ALOGW("Untrusted touch due to occlusion by %s/%d", occlusionInfo.obscuringPackage.c_str(),
occlusionInfo.obscuringUid);
return false;
}
if (occlusionInfo.obscuringOpacity > mMaximumObscuringOpacityForTouch) {
ALOGW("Untrusted touch due to occlusion by %s/%d (obscuring opacity = "
"%.2f, maximum allowed = %.2f)",
occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid,
occlusionInfo.obscuringOpacity, mMaximumObscuringOpacityForTouch);
return false;
}
return true;
}
參考文獻(xiàn)
https://developer.android.google.cn/about/versions/12/behavior-changes-all#untrusted-touch-events