Android 7+ 检测并禁用上层绘制应用的可行方案问询
Hey there! Great question—detecting overlay windows (even transparent ones) is a critical security measure to block tapjacking attacks, so it’s smart you’re moving past the outdated /proc hacks that no longer work on modern Android versions. Let’s break down the official, compliant ways to handle this:
1. Accessibility Service(最可靠的实时检测方案)
Android’s Accessibility Service is the go-to official tool for monitoring window state changes. It lets you listen when windows are created, destroyed, or modified—perfect for spotting overlays on top of your app.
步骤实现:
创建Accessibility Service类
重写onAccessibilityEvent来捕获窗口状态变化,检查是否有外部窗口覆盖在你的应用之上:public class OverlayDetectAccessibilityService extends AccessibilityService { private static final String MY_APP_PACKAGE = "com.your.secure.app"; @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { AccessibilityNodeInfo rootNode = getRootInActiveWindow(); if (rootNode == null) return; String overlayPackage = rootNode.getPackageName().toString(); // 先确认当前前台应用是我们的App,再判断是否有外部覆盖层 ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> foregroundProcesses = am.getRunningAppProcesses(); if (foregroundProcesses != null) { for (ActivityManager.RunningAppProcessInfo process : foregroundProcesses) { if (process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && process.processName.equals(MY_APP_PACKAGE)) { if (!overlayPackage.equals(MY_APP_PACKAGE)) { // 检测到外部覆盖层! Log.w("OverlayAlert", "Potential tapjacking risk from: " + overlayPackage); // 这里可以触发你的安全告警逻辑 } } } } rootNode.recycle(); // 记得回收节点,避免内存泄漏 } } @Override public void onInterrupt() { // 服务中断时的处理逻辑 } }配置服务权限
在res/xml目录下创建accessibility_service_config.xml:<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged" android:accessibilityFeedbackType="feedbackGeneric" android:canRetrieveWindowContent="true" android:description="@string/accessibility_service_desc" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"/>在Manifest注册服务
<service android:name=".OverlayDetectAccessibilityService" android:exported="false" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService"/> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config"/> </service>注意:用户必须手动在系统设置中启用你的辅助服务——这是Android的安全要求,无法静默获取权限。
2. Overlay Manager(API 26+, Android 8.0+)
对于Android 8.0及以上设备,OverlayManager API可以查询已获得SYSTEM_ALERT_WINDOW权限的应用(这类应用才有能力显示覆盖层)。它适合预先排查哪些应用存在潜在的覆盖风险。
示例代码:
OverlayManager overlayManager = (OverlayManager) getSystemService(Context.OVERLAY_SERVICE); // 获取所有能覆盖我们App的应用列表 List<OverlayInfo> overlayInfos = overlayManager.getOverlayInfosForTarget(MY_APP_PACKAGE, OverlayManager.TYPE_ALL); for (OverlayInfo info : overlayInfos) { Log.d("OverlayApps", "App with overlay permission: " + info.packageName); }
它无法提供实时覆盖检测,但可以和Accessibility Service配合,形成分层的安全防护体系。
3. 补充防护:FLAG_SECURE
虽然这不是检测方法,但给应用窗口添加FLAG_SECURE可以阻止截屏和录屏——即使有覆盖层绕过检测,也能避免界面内容被窃取:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); setContentView(R.layout.activity_main); }
关键注意事项
- 权限限制: 从Android 10(API 29)开始,如果你需要获取其他应用的包名,可能需要申请
QUERY_ALL_PACKAGES权限(除非你只针对特定已知恶意包检测)。记得在Google Play listing中说明该权限的用途。 - 无静默权限: 所有检测方案都需要用户明确授权(要么启用辅助服务,要么授予
SYSTEM_ALERT_WINDOW权限),这是符合Android安全模型的必要条件。
内容的提问来源于stack exchange,提问作者kkazakov

