转载请标明出处:

https://blog.csdn.net/shift_wwx/article/details/80249595

 

相关资源:

Android Runtime Permission 详解

android GrantPermissionsActivity 详解

AppOps 对于Normal permission 的控制

Android native 权限控制流程

AppOps 中setUidMode 和setMode区别

android M 之前应用权限和M 之后的应用权限控制

Provider 权限详解

 

前言:

在Android M 之后出现了Runtime Permission(详细看Android Runtime permission 详解),相对的之前出现的都称为install time permission。

在Activity requestPermissions之后会提示用户是否允许的dialog,当选择允许的时候,会触发grantRuntimePermission,这一篇博文主要就是分析这个函数的全过程。

 

调用方式:

通过PackageManger里面的接口调用

    @SystemApi    @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)    public abstract void grantRuntimePermission(@NonNull String packageName,            @NonNull String permissionName, @NonNull UserHandle user);

注意,这里是system api,第三方应用是无法获取这个接口,那就限制了如果想要获取权限,必须通过request permission 来申请。

最终调用到PMS中:

    @Override    public void grantRuntimePermission(String packageName, String name, final int userId) {        grantRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);    }
    private void grantRuntimePermission(String packageName, String name, final int userId,            boolean overridePolicy) {        if (!sUserManager.exists(userId)) {//确认user id存在            Log.e(TAG, "No such user:" + userId);            return;        }        final int callingUid = Binder.getCallingUid();//确定调用端app 的uid        mContext.enforceCallingOrSelfPermission(//需要app端注册GRANT_RUNTIME_PERMISSIONS 权限,不然会抛出exception                android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,                "grantRuntimePermission");        enforceCrossUserPermission(callingUid, userId,//需要INTERACT_ACROSS_USERS_FULL 权限,也会抛出exception                true /* requireFullPermission */, true /* checkShell */,                "grantRuntimePermission");        final int uid;        final PackageSetting ps;        synchronized (mPackages) {            final PackageParser.Package pkg = mPackages.get(packageName);//packageName 正确性            if (pkg == null) {                throw new IllegalArgumentException("Unknown package: " + packageName);            }            final BasePermission bp = mSettings.mPermissions.get(name);//permission name 正确性            if (bp == null) {                throw new IllegalArgumentException("Unknown permission: " + name);            }            ps = (PackageSetting) pkg.mExtras;            if (ps == null                    || filterAppAccessLPr(ps, callingUid, userId)) {                throw new IllegalArgumentException("Unknown package: " + packageName);            }            enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);//app将该permission 注册到AndroidManifest中                                                              //并且该permission 是Runtime 或者是development permission            // If a permission review is required for legacy apps we represent            // their permissions as always granted runtime ones since we need            // to keep the review required permission flag per user while an            // install permission's state is shared across all users.            if (mPermissionReviewRequired //对于legacy apps不做处理                    && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M                    && bp.isRuntime()) {                return;            }            uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);            final PermissionsState permissionsState = ps.getPermissionsState();            final int flags = permissionsState.getPermissionFlags(name, userId);            if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {                throw new SecurityException("Cannot grant system fixed permission "                        + name + " for package " + packageName);            }            if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {                throw new SecurityException("Cannot grant policy fixed permission "                        + name + " for package " + packageName);            }            if (bp.isDevelopment()) {                // Development permissions must be handled specially, since they are not                // normal runtime permissions.  For now they apply to all users.                if (permissionsState.grantInstallPermission(bp) !=                        PermissionsState.PERMISSION_OPERATION_FAILURE) {                    scheduleWriteSettingsLocked();                }                return;            }            if (ps.getInstantApp(userId) && !bp.isInstant()) {                throw new SecurityException("Cannot grant non-ephemeral permission"                        + name + " for package " + packageName);            }            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {                Slog.w(TAG, "Cannot grant runtime permission to a legacy app");                return;            }            final int result = permissionsState.grantRuntimePermission(bp, userId);            switch (result) {                case PermissionsState.PERMISSION_OPERATION_FAILURE: {                    return;                }                case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {                    final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);                    mHandler.post(new Runnable() {                        @Override                        public void run() {                            killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);                        }                    });                }                break;            }            if (bp.isRuntime()) {                logPermissionGranted(mContext, name, packageName);            }            mOnPermissionChangeListeners.onPermissionsChanged(uid);            // Not critical if that is lost - app has to request again.            mSettings.writeRuntimePermissionsForUserLPr(userId, false);        }        // Only need to do this if user is initialized. Otherwise it's a new user        // and there are no processes running as the user yet and there's no need        // to make an expensive call to remount processes for the changed permissions.        if (READ_EXTERNAL_STORAGE.equals(name)                || WRITE_EXTERNAL_STORAGE.equals(name)) {            final long token = Binder.clearCallingIdentity();            try {                if (sUserManager.isInitialized(userId)) {                    StorageManagerInternal storageManagerInternal = LocalServices.getService(                            StorageManagerInternal.class);                    storageManagerInternal.onExternalStoragePolicyChanged(uid, packageName);                }            } finally {                Binder.restoreCallingIdentity(token);            }        }    }

主要注意 3 个地方:

1、permissionsState.grantRuntimePermission(bp, userId);

    public int grantRuntimePermission(BasePermission permission, int userId) {        enforceValidUserId(userId);        if (userId == UserHandle.USER_ALL) {//这个操作不能针对所有用户,只能针对当前用户            return PERMISSION_OPERATION_FAILURE;        }        return grantPermission(permission, userId);    }
    private int grantPermission(BasePermission permission, int userId) {        if (hasPermission(permission.name, userId)) {//确认是否已经grant            return PERMISSION_OPERATION_FAILURE;        }        final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));        final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;        PermissionData permissionData = ensurePermissionData(permission);        if (!permissionData.grant(userId)) {//这里就是终点,修改PermissionData 中PermissionState 的 mGranted属性            return PERMISSION_OPERATION_FAILURE;        }        if (hasGids) {            final int[] newGids = computeGids(userId);            if (oldGids.length != newGids.length) {                return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;            }        }        return PERMISSION_OPERATION_SUCCESS;    }

 

2、mOnPermissionChangeListeners.onPermissionsChanged(uid);

        private void handleOnPermissionsChanged(int uid) {            final int count = mPermissionListeners.beginBroadcast();            try {                for (int i = 0; i < count; i++) {                    IOnPermissionsChangeListener callback = mPermissionListeners                            .getBroadcastItem(i);                    try {                        callback.onPermissionsChanged(uid);                    } catch (RemoteException e) {                        Log.e(TAG, "Permission listener is dead", e);                    }                }            } finally {                mPermissionListeners.finishBroadcast();            }        }    }

给客户端注册I OnPermissionsChangeListener 的callback 用,提示grant 成功。

 

3、mSettings.writeRuntimePermissionsForUserLPr(userId, false);

    public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {        if (sync) {            mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);        } else {            mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);        }    }
        public void writePermissionsForUserAsyncLPr(int userId) {            final long currentTimeMillis = SystemClock.uptimeMillis();            if (mWriteScheduled.get(userId)) {                mHandler.removeMessages(userId);                // If enough time passed, write without holding off anymore.                final long lastNotWrittenMutationTimeMillis = mLastNotWrittenMutationTimesMillis                        .get(userId);                final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis                        - lastNotWrittenMutationTimeMillis;                if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_PERMISSIONS_DELAY_MILLIS) {                    mHandler.obtainMessage(userId).sendToTarget();                    return;                }                // Hold off a bit more as settings are frequently changing.                final long maxDelayMillis = Math.max(lastNotWrittenMutationTimeMillis                        + MAX_WRITE_PERMISSIONS_DELAY_MILLIS - currentTimeMillis, 0);                final long writeDelayMillis = Math.min(WRITE_PERMISSIONS_DELAY_MILLIS,                        maxDelayMillis);                Message message = mHandler.obtainMessage(userId);                mHandler.sendMessageDelayed(message, writeDelayMillis);            } else {                mLastNotWrittenMutationTimesMillis.put(userId, currentTimeMillis);                Message message = mHandler.obtainMessage(userId);                mHandler.sendMessageDelayed(message, WRITE_PERMISSIONS_DELAY_MILLIS);                mWriteScheduled.put(userId, true);            }        }

这个函数主要异步处理,首先确认mWriteScheduled 是否在处理userId,如果没有就添加进去,200ms 后发出消息开始处理;如果已经在处理,计算出最合适的delay 处理,可以看出系统给定的一次操作最长是2秒。

最后会在mHandler 中的handleMessage 中处理:

            @Override            public void handleMessage(Message message) {                final int userId = message.what;                Runnable callback = (Runnable) message.obj;                writePermissionsSync(userId);                if (callback != null) {                    callback.run();                }            }

其中不管同步异步最终调用的还是writePermissionSync:

        private void writePermissionsSync(int userId) {            AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId));            ArrayMap> permissionsForPackage = new ArrayMap<>();            ArrayMap> permissionsForSharedUser = new ArrayMap<>();            synchronized (mLock) {                mWriteScheduled.delete(userId);                final int packageCount = mPackages.size();                for (int i = 0; i < packageCount; i++) {                    String packageName = mPackages.keyAt(i);                    PackageSetting packageSetting = mPackages.valueAt(i);                    if (packageSetting.sharedUser == null) {                        PermissionsState permissionsState = packageSetting.getPermissionsState();                        List permissionsStates = permissionsState                                .getRuntimePermissionStates(userId);                        if (!permissionsStates.isEmpty()) {                            permissionsForPackage.put(packageName, permissionsStates);                        }                    }                }                final int sharedUserCount = mSharedUsers.size();                for (int i = 0; i < sharedUserCount; i++) {                    String sharedUserName = mSharedUsers.keyAt(i);                    SharedUserSetting sharedUser = mSharedUsers.valueAt(i);                    PermissionsState permissionsState = sharedUser.getPermissionsState();                    List permissionsStates = permissionsState                            .getRuntimePermissionStates(userId);                    if (!permissionsStates.isEmpty()) {                        permissionsForSharedUser.put(sharedUserName, permissionsStates);                    }                }            }            FileOutputStream out = null;            try {                out = destination.startWrite();                XmlSerializer serializer = Xml.newSerializer();                serializer.setOutput(out, StandardCharsets.UTF_8.name());                serializer.setFeature(                        "http://xmlpull.org/v1/doc/features.html#indent-output", true);                serializer.startDocument(null, true);                serializer.startTag(null, TAG_RUNTIME_PERMISSIONS);                String fingerprint = mFingerprints.get(userId);                if (fingerprint != null) {                    serializer.attribute(null, ATTR_FINGERPRINT, fingerprint);                }                final int packageCount = permissionsForPackage.size();                for (int i = 0; i < packageCount; i++) {                    String packageName = permissionsForPackage.keyAt(i);                    List permissionStates = permissionsForPackage.valueAt(i);                    serializer.startTag(null, TAG_PACKAGE);                    serializer.attribute(null, ATTR_NAME, packageName);                    writePermissions(serializer, permissionStates);                    serializer.endTag(null, TAG_PACKAGE);                }                final int sharedUserCount = permissionsForSharedUser.size();                for (int i = 0; i < sharedUserCount; i++) {                    String packageName = permissionsForSharedUser.keyAt(i);                    List permissionStates = permissionsForSharedUser.valueAt(i);                    serializer.startTag(null, TAG_SHARED_USER);                    serializer.attribute(null, ATTR_NAME, packageName);                    writePermissions(serializer, permissionStates);                    serializer.endTag(null, TAG_SHARED_USER);                }                serializer.endTag(null, TAG_RUNTIME_PERMISSIONS);                // Now any restored permission grants that are waiting for the apps                // in question to be installed.  These are stored as per-package                // TAG_RESTORED_RUNTIME_PERMISSIONS blocks, each containing some                // number of individual permission grant entities.                if (mRestoredUserGrants.get(userId) != null) {                    ArrayMap> restoredGrants =                            mRestoredUserGrants.get(userId);                    if (restoredGrants != null) {                        final int pkgCount = restoredGrants.size();                        for (int i = 0; i < pkgCount; i++) {                            final ArraySet pkgGrants =                                    restoredGrants.valueAt(i);                            if (pkgGrants != null && pkgGrants.size() > 0) {                                final String pkgName = restoredGrants.keyAt(i);                                serializer.startTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);                                serializer.attribute(null, ATTR_PACKAGE_NAME, pkgName);                                final int N = pkgGrants.size();                                for (int z = 0; z < N; z++) {                                    RestoredPermissionGrant g = pkgGrants.valueAt(z);                                    serializer.startTag(null, TAG_PERMISSION_ENTRY);                                    serializer.attribute(null, ATTR_NAME, g.permissionName);                                    if (g.granted) {                                        serializer.attribute(null, ATTR_GRANTED, "true");                                    }                                    if ((g.grantBits&FLAG_PERMISSION_USER_SET) != 0) {                                        serializer.attribute(null, ATTR_USER_SET, "true");                                    }                                    if ((g.grantBits&FLAG_PERMISSION_USER_FIXED) != 0) {                                        serializer.attribute(null, ATTR_USER_FIXED, "true");                                    }                                    if ((g.grantBits&FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0) {                                        serializer.attribute(null, ATTR_REVOKE_ON_UPGRADE, "true");                                    }                                    serializer.endTag(null, TAG_PERMISSION_ENTRY);                                }                                serializer.endTag(null, TAG_RESTORED_RUNTIME_PERMISSIONS);                            }                        }                    }                }                serializer.endDocument();                destination.finishWrite(out);                if (Build.FINGERPRINT.equals(fingerprint)) {                    mDefaultPermissionsGranted.put(userId, true);                }            // Any error while writing is fatal.            } catch (Throwable t) {                Slog.wtf(PackageManagerService.TAG,                        "Failed to write settings, restoring backup", t);                destination.failWrite(out);            } finally {                IoUtils.closeQuietly(out);            }        }

里面就是将对应的runtime permission 存放在runtime-permissions.xml 中,主要就是将之前保存的PermissionStates中的mGranted属性和mFlags属性存放在这里:

        private void writePermissions(XmlSerializer serializer,                List permissionStates) throws IOException {            for (PermissionState permissionState : permissionStates) {                serializer.startTag(null, TAG_ITEM);                serializer.attribute(null, ATTR_NAME,permissionState.getName());                serializer.attribute(null, ATTR_GRANTED,                        String.valueOf(permissionState.isGranted()));                serializer.attribute(null, ATTR_FLAGS,                        Integer.toHexString(permissionState.getFlags()));                serializer.endTag(null, TAG_ITEM);            }        }

最终的xml 如下(详见/data/system/users/0/runtime-permissions.xml):

                        
                            

 

 

 

 

 

 

 

 

更多相关文章

  1. Android(安卓)Interface Definition Language(AIDL)
  2. ubuntu 14.04 配置android adb 环境
  3. android 调用人人网sdk登录页面 成功后不跳转 只停留在白色Oauth
  4. android如何调用显示和隐藏系统默认的输入法
  5. Android(安卓)隐式调用 intent
  6. android 发送短信
  7. Android(安卓)“Not granting permission” error
  8. android音乐播放器Service的生命周期分析
  9. AbstractProcessor注解处理器

随机推荐

  1. Android(安卓)Studio中常用设置与快捷键
  2. Android 开发技术周报 Issue#299
  3. 【Android】View组件
  4. android中setVisibility的用法
  5. Android UI性能问题探讨
  6. 下载 android 源码错误curl: (6) couldn'
  7. 聚焦 Android 11:游戏开发新工具
  8. Android-透明状态栏
  9. android jni (jni_onload方式)
  10. Android中使用SQLite数据库详解