Android Framework默认授予第三方APP悬浮窗权限

需求
有第三方应用启动会请求悬浮窗权限,因为代码中没有做规避,会弹出请求窗口,点击确认后还要跳到设置中进行授权确认.有点麻烦,想去掉请求窗口,默认授予悬浮窗权限给APP.

悬浮窗默认实现原理
AppOpsManager 是Google在Android4.3里面引进的应用程序操作(权限)的管理类,核心实现类为AppOpsService,这里主要是修改AppOpsService.
在framework中,将某一权限称为Op,即operation,
原理是在上层APP启动请求权限时,判定是请求悬浮窗,如果未授权则强制设置为可修改,并把悬浮窗权限写入到Op中.

int checkop(String op,int uid,String packageName)判断应用是否含有某个权限
AppOpsManager.checkOp()最终会调用到AppOpsService.checkOperationUnchecked(),
先看下此函数的实现

private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
            boolean raw) {
    RestrictionBypass bypass;
    try {
        bypass = verifyAndGetBypass(uid, packageName, null);
    } catch (SecurityException e) {
        Slog.e(TAG, "checkOperation", e);
        return AppOpsManager.opToDefaultMode(code);
    }

    if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
        return AppOpsManager.MODE_IGNORED;
    }
    synchronized (this) {
        if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
            return AppOpsManager.MODE_IGNORED;
        }
        code = AppOpsManager.opToSwitch(code);
        UidState uidState = getUidStateLocked(uid, false);
        if (uidState != null && uidState.opModes != null
                && uidState.opModes.indexOfKey(code) >= 0) {
            final int rawMode = uidState.opModes.get(code);
            return raw ? rawMode : uidState.evalMode(code, rawMode);
        }
        Op op = getOpLocked(code, uid, packageName, null, bypass, false);
        if (op == null) {
            return AppOpsManager.opToDefaultMode(code);
        }
        return raw ? op.mode : op.evalMode();
    }
}

可以看到这句Op op = getOpLocked(code, uid, packageName, null, bypass, false)
类似noteOperationUnchecked函数也会调到这句getOpLocked,我们主要是修改这个getOpLocked函数.

根据包名授予悬浮窗权限
在Android11上实测通过,理论上安卓7到13都是可以的,Android13代码与11一样,只是行数不一样.
修改
frameworks/base/services/core/java/com/android/server/appop/AppOpsService.java

ff --git a/frameworks/base/services/core/java/com/android/server/appop/AppOpsService.java b/frameworks/base/services/core/java/com/android/server/appop/AppOpsService.java
index c81a306b27..0d2a29a20c 100644
--- a/frameworks/base/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/frameworks/base/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3960,6 +3960,14 @@ public class AppOpsService extends IAppOpsService.Stub {
         return ops;
     }
 
+    // 权限白名单应用,用包名做判断
+    private boolean isInWhiteList(String pkg) {
+        if ("com.test".equals(pkg)){
+            return true;
+        }
+        return false;
+    }
+
     private void scheduleWriteLocked() {
         if (!mWriteScheduled) {
             mWriteScheduled = true;
@@ -3990,10 +3998,39 @@ public class AppOpsService extends IAppOpsService.Stub {
      */
     private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
             @Nullable String attributionTag, @Nullable RestrictionBypass bypass, boolean edit) {
+
+        boolean isWhiteList = false;
+        if (AppOpsManager.OP_SYSTEM_ALERT_WINDOW == code && isInWhiteList(packageName)) {
+            isWhiteList = true;
+            edit = true; // 设置为op可修改,否则后面会返回null
+        }
+
         Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, edit);
         if (ops == null) {
             return null;
         }
+
+        if (isWhiteList) {
+            boolean write = false;
+            Op op = ops.get(code);
+            if (op == null) { // 为null则写
+                if (ops.uidState != null) {
+                    op = new Op(ops.uidState, ops.packageName, code, uid);
+                    write = true;
+                }
+            } else if (op.mode != AppOpsManager.MODE_ALLOWED) { // 未授权则写
+                write = true;
+            }
+
+            if (write) {
+                op.mode = AppOpsManager.MODE_ALLOWED; // 强制设置为授权了
+                ops.put(code, op);
+                if (ops.uidState != null && ops.uidState.pkgOps != null) {
+                    ops.uidState.pkgOps.put(packageName, ops);
+                }
+            }
+        }
+
         return getOpLocked(ops, code, uid, edit);
     }

完整代码如下

private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
        @Nullable String attributionTag, @Nullable RestrictionBypass bypass, boolean edit) {

    boolean isWhiteList = false;
    if (AppOpsManager.OP_SYSTEM_ALERT_WINDOW == code && isInWhiteList(packageName)) {
        isWhiteList = true;
        edit = true;
    }

    Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, edit);
    if (ops == null) {
        return null;
    }

    if (isWhiteList) {
        boolean write = false;
        Op op = ops.get(code);
        if (op == null) {
            if (ops.uidState != null) {
                op = new Op(ops.uidState, ops.packageName, code, uid);
                write = true;
            }
        } else if (op.mode != AppOpsManager.MODE_ALLOWED) {
            write = true;
        }

        if (write) {
            op.mode = AppOpsManager.MODE_ALLOWED;
            ops.put(code, op);
            if (ops.uidState != null && ops.uidState.pkgOps != null) {
                ops.uidState.pkgOps.put(packageName, ops);
            }
        }
    }

    return getOpLocked(ops, code, uid, edit);
}

private boolean isInWhiteList(String pkg) {
    if ("com.test".equals(pkg)){
        return true;
    }
    return false;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值