Android12特性“不受信任的触摸事件被屏蔽”其他细节

Android12特性“不受信任的触摸事件被屏蔽”其他细节

android12-release
Android 12关于Input触摸事件的行为变更 这篇介绍了input实际的拦截findTouchedWindowTargetsLocked


“不受信任的触摸事件被屏蔽”相关属性

mBlockUntrustedTouchesMode

  • 三种属性值:DISABLED不拦截;PERMISSIVE拦截判断最后没拦截;BLOCK拦截
    frameworks\base\core\java\android\hardware\input\InputManager.java
    frameworks/native/libs/input/android/os/BlockUntrustedTouchesMode.aidl
    /** @hide */
    public static final int[] BLOCK_UNTRUSTED_TOUCHES_MODES = {
            BlockUntrustedTouchesMode.DISABLED,
            BlockUntrustedTouchesMode.PERMISSIVE,
            BlockUntrustedTouchesMode.BLOCK
    };

在这里插入图片描述

  • block_untrusted_touches设置/获取:Settings.Global.BLOCK_UNTRUSTED_TOUCHES_MODE改变 -- InputManagerService.java -- JNI -- InputDispatcher.cpp
    在这里插入图片描述在这里插入图片描述
    adb shell settings get global block_untrusted_touches
    adb shell settings put global block_untrusted_touches 0
  • 单个应用设置
    adb shell am compat disable BLOCK_UNTRUSTED_TOUCHES com.example.app
    adb shell am compat reset BLOCK_UNTRUSTED_TOUCHES com.example.app
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述在这里插入图片描述

frameworks/base/cmds/am/src/com/android/commands/am/Am.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
frameworks/base/services/core/java/com/android/server/compat/PlatformCompat.java
frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
frameworks/base/services/core/java/com/android/server/wm/WindowState.java
frameworks/base/core/java/android/app/compat/CompatChanges.java
frameworks/base/core/java/android/app/compat/ChangeIdStateCache.java
frameworks/base/core/java/android/app/compat/ChangeIdStateQuery.java

TouchOcclusionInfo

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.h

struct TouchOcclusionInfo {
    bool hasBlockingOcclusion;
    float obscuringOpacity;
    std::string obscuringPackage;
    int32_t obscuringUid;
    std::vector<std::string> debugInfo;
};
  • computeTouchOcclusionInfoLocked赋值
    frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
  1. hasBlockingOcclusion 界面InputWindowInfo属性touchOcclusionMode==BLOCK_UNTRUSTED时为true
  2. obscuringOpacity 界面InputWindowInfo属性touchOcclusionMode==USE_OPACITY时计算透明度
  3. obscuringUid、obscuringPackage 界面InputWindowInfo属性touchOcclusionMode!=ALLOW时会赋值
  4. debugInfo 当DEBUG_TOUCH_OCCLUSION打开时赋值界面信息InputWindowInfo
  5. canBeObscuredBy(windowHandle, otherHandle)当InputWindowHandle可见visible、不信任trustedOverlay等时赋值,否则,返回TouchOcclusionInfo默认值
InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLocked(
        const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
    const InputWindowInfo* windowInfo = windowHandle->getInfo();
    int32_t displayId = windowInfo->displayId;
    const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
    TouchOcclusionInfo info;
    info.hasBlockingOcclusion = false;
    info.obscuringOpacity = 0;
    info.obscuringUid = -1;
    std::map<int32_t, float> opacityByUid;
    for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
        if (windowHandle == otherHandle) {
            break; // All future windows are below us. Exit early.
        }
        const InputWindowInfo* otherInfo = otherHandle->getInfo();
        if (canBeObscuredBy(windowHandle, otherHandle) && otherInfo->frameContainsPoint(x, y) &&
            !haveSameApplicationToken(windowInfo, otherInfo)) {
            if (DEBUG_TOUCH_OCCLUSION) {
                info.debugInfo.push_back(
                        dumpWindowForTouchOcclusion(otherInfo, /* isTouchedWindow */ false));
            }
            // canBeObscuredBy() has returned true above, which means this window is untrusted, so
            // we perform the checks below to see if the touch can be propagated or not based on the
            // window's touch occlusion mode
            if (otherInfo->touchOcclusionMode == TouchOcclusionMode::BLOCK_UNTRUSTED) {
                info.hasBlockingOcclusion = true;
                info.obscuringUid = otherInfo->ownerUid;
                info.obscuringPackage = otherInfo->packageName;
                break;
            }
            if (otherInfo->touchOcclusionMode == TouchOcclusionMode::USE_OPACITY) {
                uint32_t uid = otherInfo->ownerUid;
                float opacity =
                        (opacityByUid.find(uid) == opacityByUid.end()) ? 0 : opacityByUid[uid];
                // Given windows A and B:
                // opacity(A, B) = 1 - [1 - opacity(A)] * [1 - opacity(B)]
                opacity = 1 - (1 - opacity) * (1 - otherInfo->alpha);
                opacityByUid[uid] = opacity;
                if (opacity > info.obscuringOpacity) {
                    info.obscuringOpacity = opacity;
                    info.obscuringUid = uid;
                    info.obscuringPackage = otherInfo->packageName;
                }
            }
        }
    }
    if (DEBUG_TOUCH_OCCLUSION) {
        info.debugInfo.push_back(
                dumpWindowForTouchOcclusion(windowInfo, /* isTouchedWindow */ true));
    }
    return info;
}
  • !isTouchTrustedLocked根据TouchOcclusionInfo判断是否拦截
  1. hasBlockingOcclusion 界面InputWindowInfo属性touchOcclusionMode==BLOCK_UNTRUSTED时拦截
  2. 模糊不透明度obscuringOpacity大于mMaximumObscuringOpacityForTouch时拦截(mMaximumObscuringOpacityForTouch为Settings.Global.getUriFor(Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH)属性值,默认0.8f)
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;
}

什么情况不拦截

回顾上边属性,并查看Android 12关于Input触摸事件的行为变更图代码:

// Drop events that can't be trusted due to occlusion
if (newTouchedWindowHandle != nullptr &&
    mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) {
    TouchOcclusionInfo occlusionInfo =
            computeTouchOcclusionInfoLocked(newTouchedWindowHandle, 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());
            }
        }
        onUntrustedTouchLocked(occlusionInfo.obscuringPackage);
        if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
            ALOGW("Dropping untrusted touch event due to %s/%d",
                  occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
            newTouchedWindowHandle = nullptr;
        }
    }
}
  1. BlockUntrustedTouchesMode为DISABLED、PERMISSIVE不拦截
  2. 当窗口InputWindowHandle可见visible、信任trustedOverlay时TouchOcclusionInfo默认!isTouchTrustedLocked为false,不拦截
  3. 当窗口InputWindowInfo属性touchOcclusionMode=ALLOW时TouchOcclusionInfo默认!isTouchTrustedLocked为false,不拦截
  4. 设置adb shell am compat disable BLOCK_UNTRUSTED_TOUCHES com.example.app时com.example.app该应用不拦截(实质同第3种touchOcclusionMode=ALLOW一样)

拦截通知弹框

onUntrustedTouchLocked(occlusionInfo.obscuringPackage) -- JNI -- InputManagerService.java
在这里插入图片描述

  1. UNTRUSTED_TOUCHES_TOAST默认关闭Toast弹框
  2. PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST 配置不弹框
private static final String[] PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST = {
       "com.snapchat.android" // b/173297887
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xhBruce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值