android grantRuntimePermission 详解
转载请标明出处:
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):
更多相关文章
- 调试android通过jni调用的C++代码
- android grantRuntimePermission 详解
- Android(安卓)Interface Definition Language(AIDL)
- ubuntu 14.04 配置android adb 环境
- android 调用人人网sdk登录页面 成功后不跳转 只停留在白色Oauth
- android如何调用显示和隐藏系统默认的输入法
- Android(安卓)隐式调用 intent
- android 发送短信
- Android(安卓)“Not granting permission” error