[092]untrusted-touch-events

背景

來(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容