平台

RK3288 + Android 7.1

需求

在高版本的SDK中, 第三方应用申请悬浮窗的权限受到了过一步的限制.
除了要在应用中声明对权限的申请:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

还需要打开设置中的权限:

应用可以通过代码检测权限是否已获取:

            AppOpsManager opsMgr = (AppOpsManager)getSystemService(APP_OPS_SERVICE);            int res = opsMgr.checkOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, Process.myUid(), getPackageName());            if(res != AppOpsManager.MODE_ALLOWED){                showToast(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW + " not allowed");            }

有可能会抛出异常:

java.lang.SecurityException: com.android.myapp from uid 10066 not allowed to perform SYSTEM_ALERT_WINDOW

若需要默认打开, 需要修改相关代码

修改

frameworks/base/services/core/java/com/android/server/AppOpsService.java

    private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {    //判断是否包含在白名单中, 并将其置为edit 置为 true.    //否则, 默认情况下, 则返回空, 导致在应用或其它服务获取packageName时, 发现其并未获取任何操作权限        edit |= checkIfInWhitelist(packageName);        UidState uidState = getUidStateLocked(uid, edit);        if (uidState == null) {            return null;        }        if (uidState.pkgOps == null) {            if (!edit) {                return null;            }            uidState.pkgOps = new ArrayMap<>();        }        Ops ops = uidState.pkgOps.get(packageName);        if (ops == null) {            if (!edit) {                return null;            }            boolean isPrivileged = false;            // This is the first time we have seen this package name under this uid,            // so let's make sure it is valid.            if (uid != 0) {                final long ident = Binder.clearCallingIdentity();                try {                    int pkgUid = -1;                    try {                        ApplicationInfo appInfo = ActivityThread.getPackageManager()                                .getApplicationInfo(packageName,                                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING,                                        UserHandle.getUserId(uid));                        if (appInfo != null) {                            pkgUid = appInfo.uid;                            isPrivileged = (appInfo.privateFlags                                    & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;                        } else {                            if ("media".equals(packageName)) {                                pkgUid = Process.MEDIA_UID;                                isPrivileged = false;                            } else if ("audioserver".equals(packageName)) {                                pkgUid = Process.AUDIOSERVER_UID;                                isPrivileged = false;                            } else if ("cameraserver".equals(packageName)) {                                pkgUid = Process.CAMERASERVER_UID;                                isPrivileged = false;                            }                        }                    } catch (RemoteException e) {                        Slog.w(TAG, "Could not contact PackageManager", e);                    }                    if (pkgUid != uid) {                        // Oops!  The package name is not valid for the uid they are calling                        // under.  Abort.                        RuntimeException ex = new RuntimeException("here");                        ex.fillInStackTrace();                        Slog.w(TAG, "Bad call: specified package " + packageName                                + " under uid " + uid + " but it is really " + pkgUid, ex);                        return null;                    }                } finally {                    Binder.restoreCallingIdentity(ident);                }            }            ops = new Ops(packageName, uidState, isPrivileged);            if(checkIfInWhitelist(packageName)){                //添加默认权限并设置为允许, 这里只加了SYTEM_ALERT_WINDOW                Op op = new Op(ops.uidState.uid, ops.packageName, AppOpsManager.OP_SYSTEM_ALERT_WINDOW);                op.mode = AppOpsManager.MODE_ALLOWED;                ops.put(op.op, op);            }            uidState.pkgOps.put(packageName, ops);        }        return ops;    }    //allow special package for some permission    //把需要添加默认权限的应用包名加入到白名单中.    private boolean checkIfInWhitelist(String pkg){        if("com.android.testapp".equals(pkg)){            return true;        }        //....更多应用        return false;    }

相关代码

APP安装后, 权限为默认值, 即未变更, 默认值:
frameworks/base/core/java/android/app/AppOpsManager.java

    public static final int OP_NONE = -1;//..........    /** @hide */    public static final int OP_WRITE_SETTINGS = 23;    /** @hide */    public static final int OP_SYSTEM_ALERT_WINDOW = 24;    /**     * This specifies the default mode for each operation.     */    private static int[] sOpDefaultMode = new int[] {            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_DEFAULT, // OP_WRITE_SETTINGS            AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_DEFAULT, // OP_GET_USAGE_STATS            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA            AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ERRORED,  // OP_MOCK_LOCATION            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,  // OP_TURN_ON_SCREEN            AppOpsManager.MODE_ALLOWED,            AppOpsManager.MODE_ALLOWED,  // OP_RUN_IN_BACKGROUND    };

AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW

  • 设置中获取应用的权限
    packages/apps/Settings/src/com/android/settings/applications/AppStateAppOpsBridge.java
    public PermissionState getPermissionInfo(String pkg, int uid) {        PermissionState permissionState = new PermissionState(pkg, new UserHandle(UserHandle                .getUserId(uid)));        try {            permissionState.packageInfo = mIPackageManager.getPackageInfo(pkg,                    PackageManager.GET_PERMISSIONS | PackageManager.MATCH_UNINSTALLED_PACKAGES,                    permissionState.userHandle.getIdentifier());            // Check static permission state (whatever that is declared in package manifest)            String[] requestedPermissions = permissionState.packageInfo.requestedPermissions;            int[] permissionFlags = permissionState.packageInfo.requestedPermissionsFlags;            if (requestedPermissions != null) {                for (int i = 0; i < requestedPermissions.length; i++) {                    if (doesAnyPermissionMatch(requestedPermissions[i], mPermissions)) {                        permissionState.permissionDeclared = true;                        if ((permissionFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {                            permissionState.staticPermissionGranted = true;                            break;                        }                    }                }            }            // Check app op state.            List<PackageOps> ops = mAppOpsManager.getOpsForPackage(uid, pkg, mAppOpsOpCodes);            if (ops != null && ops.size() > 0 && ops.get(0).getOps().size() > 0) {                permissionState.appOpMode = ops.get(0).getOps().get(0).getMode();            }        } catch (RemoteException e) {            Log.w(TAG, "PackageManager is dead. Can't get package info " + pkg, e);        }        return permissionState;    }

若未变更设置项, mAppOpsManager.getOpsForPackage将返回空
若已变更, 则返回变更后的值

  • Android权限管理与AppOpsManager

更多相关文章

  1. android 8.0 自定义控件onmesure获取宽度为0
  2. android property属性property_set()&& property_get() selinux
  3. 【Based Android】Android(安卓)Sensor感应器介绍(一)重力感应加速
  4. Android中的UID、GID与应用安全
  5. Android初始ViewRoot和DecorView
  6. android web services2
  7. android.support.v7.widget.TintContextWrapper cannot be cast
  8. EasyPermission Android(安卓)6.0 最简洁的权限框架
  9. Android(安卓)获取手机联系人列表

随机推荐

  1. AndroidAZ系列:ContentProvider(All,Face
  2. Android(安卓)还可以走多久?
  3. Android dependency 'android.arch.core:
  4. Android下载 文件(APP) 并且静默安装
  5. Kotlin概述之Kotlin for Android
  6. Android比较字符串是否为空(isEmpty)
  7. Mac下获取SHA1
  8. 学习笔记之——Android中的Picasso实现圆
  9. Android(安卓)全局消息通知框架实现(类似E
  10. Installing the Android SDK