做app开发经常需求请求动态权限,比方WRITE_EXTERNAL_STORAGE
、ACCESS_FINE_LOCATION
,那么今天就从源码剖析,动态权限到底是怎样个流程,Android体系是怎样维护各个app的权限状况的,基于Android 10。对源码敏感的同学能够直接拉到底部看总结
查看权限
首要权限请求进口位于frameworks/base/core/java/android/content/Context.java
public abstract class Context {
//省掉部分代码
/**
* Determine whether <em>you</em> have been granted a particular permission.
*
* @param permission The name of the permission being checked.
*
* @return {@link PackageManager#PERMISSION_GRANTED} if you have the
* permission, or {@link PackageManager#PERMISSION_DENIED} if not.
*
* @see PackageManager#checkPermission(String, String)
* @see #checkCallingPermission(String)
*/
@PackageManager.PermissionResult
public abstract int checkSelfPermission(@NonNull String permission);
//省掉部分代码
}
checkSelfPermission()
是一个抽象办法,办法完成在Context
的子类frameworks/base/core/java/android/app/ContextImpl.java
傍边
/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context {
//省掉部分代码
@Override
public int checkSelfPermission(String permission) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
return checkPermission(permission, Process.myPid(), Process.myUid());
}
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
//获取ActivityManagerService署理方针
final IActivityManager am = ActivityManager.getService();
if (am == null) {
// Well this is super awkward; we somehow don't have an active
// ActivityManager instance. If we're testing a root or system
// UID, then they totally have whatever permission this is.
final int appId = UserHandle.getAppId(uid);
//假如是root用户或者是体系使用,直接回来已授权状况
if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission);
return PackageManager.PERMISSION_GRANTED;
}
Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold "
+ permission);
return PackageManager.PERMISSION_DENIED;
}
try {
//经过ActivityManagerService来查看权限
return am.checkPermission(permission, pid, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//省掉部分代码
}
ContextImpl
经过frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
来查看权限
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
//省掉部分代码
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
return PackageManager.PERMISSION_DENIED;
}
//注意,参数4传的-1,参数5传的true
return checkComponentPermission(permission, pid, uid, -1, true);
}
public static int checkComponentPermission(String permission, int pid, int uid,
int owningUid, boolean exported) {
//假如是AMS进程调用此办法,则直接回来已授权状况
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
return ActivityManager.checkComponentPermission(permission, uid,
owningUid, exported);
}
/** @hide */
@UnsupportedAppUsage
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
// Root, system server get to do everything.
final int appId = UserHandle.getAppId(uid);
//假如是root用户或者是体系使用,直接回来已授权状况
if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
return PackageManager.PERMISSION_GRANTED;
}
// Isolated processes don't get any permissions.
//孤立的进程不具有任何权限
if (UserHandle.isIsolated(uid)) {
return PackageManager.PERMISSION_DENIED;
}
// If there is a uid that owns whatever is being accessed, it has
// blanket access to it regardless of the permissions it requires.
//owningUid为刚刚咱们传的参数4,为-1,所以显然这儿不满意
if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
return PackageManager.PERMISSION_GRANTED;
}
// If the target is not exported, then nobody else can get to it.
//exported为刚刚咱们传的参数5,为true,所以显然这儿不满意,这儿的意思是假如方针进程不对外开放,则任何方针都无法访问
if (!exported) {
/*
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
here);
*/
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
return PackageManager.PERMISSION_GRANTED;
}
try {
//经过PackageManagerService查看权限
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//省掉部分代码
}
先是处理了一些特殊状况的逻辑,终究权限判别交由frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
来完成
public class PackageManagerService extends IPackageManager.Stub
implements PackageSender {
//省掉部分代码
@Override
public int checkUidPermission(String permName, int uid) {
final CheckPermissionDelegate checkPermissionDelegate;
synchronized (mPackages) {
if (mCheckPermissionDelegate == null) {
return checkUidPermissionImpl(permName, uid);
}
checkPermissionDelegate = mCheckPermissionDelegate;
}
//终究都履行checkUidPermissionImpl()
return checkPermissionDelegate.checkUidPermission(permName, uid,
PackageManagerService.this::checkUidPermissionImpl);
}
private int checkUidPermissionImpl(String permName, int uid) {
synchronized (mPackages) {
//先获取packageName
final String[] packageNames = getPackagesForUid(uid);
PackageParser.Package pkg = null;
final int N = packageNames == null ? 0 : packageNames.length;
for (int i = 0; pkg == null && i < N; i++) {
pkg = mPackages.get(packageNames[i]);
}
//履行PermissionManagerServiceInternal的checkUidPermission()
return mPermissionManager.checkUidPermission(permName, pkg, uid, getCallingUid());
}
}
//省掉部分代码
}
能够看到,终究会履行PermissionManagerServiceInternal
的checkUidPermission()
,checkUidPermission()
是一个抽象办法,由PermissionManagerServiceInternal
的子类PermissionManagerService.PermissionManagerServiceInternalImpl
来完成
/**
* Manages all permissions and handles permissions related tasks.
*/
public class PermissionManagerService {
//省掉部分代码
/**
* Built-in permissions. Read from system configuration files. Mapping is from
* UID to permission name.
*/
private final SparseArray<ArraySet<String>> mSystemPermissions;
private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
//省掉部分代码
@Override
public int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
int callingUid) {
//履行PermissionManagerService的checkUidPermission()办法
return PermissionManagerService.this.checkUidPermission(permName, pkg, uid, callingUid);
}
//省掉部分代码
}
private int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
int callingUid) {
//获取调用此Service的进程uid,也便是调用者的uid
final int callingUserId = UserHandle.getUserId(callingUid);
//callingUserId是否为即时使用,我称之为快使用,免安装的那种
final boolean isCallerInstantApp =
mPackageManagerInt.getInstantAppPackageName(callingUid) != null;
//uid是否为即时使用,我称之为快使用,免安装的那种
final boolean isUidInstantApp =
mPackageManagerInt.getInstantAppPackageName(uid) != null;
//获取请求权限的进程id,假如是微信请求权限,则uid指微信,经过日志打印得知,userId与callingUserId相等
final int userId = UserHandle.getUserId(uid);
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
}
if (pkg != null) {
//非常规场景的处理
if (pkg.mSharedUserId != null) {
if (isCallerInstantApp) {
return PackageManager.PERMISSION_DENIED;
}
} else if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
return PackageManager.PERMISSION_DENIED;
}
//获取该使用的授权状况,授权状况封装在PermissionState方针傍边
final PermissionsState permissionsState =
((PackageSetting) pkg.mExtras).getPermissionsState();
//假如已经授权,则回来PERMISSION_GRANTED
if (permissionsState.hasPermission(permName, userId)) {
if (isUidInstantApp) {
if (mSettings.isPermissionInstant(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
return PackageManager.PERMISSION_GRANTED;
}
}
//假如同权限组中有其他的权限已经授权了,则该组其它权限也直接授权,比方ACCESS_FINE_LOCATION授权了,ACCESS_COURSE_LOCATION也会自动授权
if (isImpliedPermissionGranted(permissionsState, permName, userId)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
//假如pkg为空,阐明PMS没有扫描到此安装包,此逻辑使用app不必考虑,经过日志,也没有走到此处
ArraySet<String> perms = mSystemPermissions.get(uid);
if (perms != null) {
if (perms.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
if (FULLER_PERMISSION_MAP.containsKey(permName)
&& perms.contains(FULLER_PERMISSION_MAP.get(permName))) {
return PackageManager.PERMISSION_GRANTED;
}
}
}
//都不满意则回来PERMISSION_DENIED
return PackageManager.PERMISSION_DENIED;
}
//省掉部分代码
}
先从PackageParser.Package
中读取mExtral
字段,此字段为PackageSetting
方针,再经过PackageSetting
读取当时使用授权状况PermissionState
。PackageParser.Package
表示从磁盘读取的APK文件的完好信息(PMS在初始化时会扫描磁盘,这儿不做详细剖析),咱们知道一个APK文件包含许多信息,包名,版本号,一切注册的组件,需求请求的权限等等,详细可参考manifest文件和gradle文件,而咱们的权限信息就在mExtral
字段傍边,而mExtral
是一个PackageSetting
方针,涉及到安装包装备变更的数据都保存在此方针中,其中咱们经过getPermissionsState()
拿到授权状况PermissionsState
,然后经过hasPermission()
判别当时请求的权限是否已经授权
public final class PermissionsState {
//省掉部分代码
@GuardedBy("mLock")
private ArrayMap<String, PermissionData> mPermissions;
/**
* Gets whether the state has a given permission for the specified
* user, regardless if this is an install or a runtime permission.
*
* @param name The permission name.
* @param userId The device user id.
* @return Whether the user has the permission.
*/
public boolean hasPermission(String name, int userId) {
enforceValidUserId(userId);
synchronized (mLock) {
if (mPermissions == null) {
return false;
}
PermissionData permissionData = mPermissions.get(name);
return permissionData != null && permissionData.isGranted(userId);
}
}
//省掉部分代码
}
由于一个ap或许涉及到多个权限请求,所以PermissionsState
里界说了一个ArrayMap
来保存一切权限的授权状况,map的key为权限称号,value为PermissionData
,PermissionData
里边界说了一个SparseArray<PermissionsState.PermissionState>
,保存一切用户对当时app指定权限的授权状况
private static final class PermissionData {
private final BasePermission mPerm;
private SparseArray<PermissionState> mUserStates = new SparseArray<>();
public PermissionData(BasePermission perm) {
mPerm = perm;
}
public PermissionData(PermissionData other) {
this(other.mPerm);
final int otherStateCount = other.mUserStates.size();
for (int i = 0; i < otherStateCount; i++) {
final int otherUserId = other.mUserStates.keyAt(i);
PermissionState otherState = other.mUserStates.valueAt(i);
mUserStates.put(otherUserId, new PermissionState(otherState));
}
}
//这儿考虑了多用户的状况
public boolean isGranted(int userId) {
if (isInstallPermission()) {
userId = UserHandle.USER_ALL;
}
PermissionState userState = mUserStates.get(userId);
if (userState == null) {
return false;
}
return userState.mGranted;
}
//假如用户点击了答应授权,则调用此办法设置
public boolean grant(int userId) {
if (!isCompatibleUserId(userId)) {
return false;
}
if (isGranted(userId)) {
return false;
}
PermissionState userState = mUserStates.get(userId);
if (userState == null) {
userState = new PermissionState(mPerm.getName());
mUserStates.put(userId, userState);
}
userState.mGranted = true;
return true;
}
//省掉部分代码
}
PermissionsState.PermissionState
则是界说了权限的称号和权限的授权状况
public final class PermissionsState {
//省掉部分代码
public static final class PermissionState {
//权限称号
private final String mName;
//是否授权
private boolean mGranted;
private int mFlags;
public PermissionState(String name) {
mName = name;
}
public PermissionState(PermissionState other) {
mName = other.mName;
mGranted = other.mGranted;
mFlags = other.mFlags;
}
public boolean isDefault() {
return !mGranted && mFlags == 0;
}
public String getName() {
return mName;
}
public boolean isGranted() {
return mGranted;
}
public int getFlags() {
return mFlags;
}
}
}
以上是Context.checkPermission()
的流程
请求权限
下面再来看看Activity.requestPermissions()
的流程,fragment的权限请求也是走的宿主Activity的权限请求流程
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback, WindowControllerCallback,
AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
//省掉部分代码
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
if (requestCode < 0) {
throw new IllegalArgumentException("requestCode should be >= 0");
}
if (mHasCurrentPermissionsRequest) {
Log.w(TAG, "Can request only one set of permissions at a time");
// Dispatch the callback with empty arrays which means a cancellation.
onRequestPermissionsResult(requestCode, new String[0], new int[0]);
return;
}
//构建Intent
Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
//发动Activity
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
mHasCurrentPermissionsRequest = true;
}
//省掉部分代码
}
经过PackageManager
构建了一个Intent,然后发动了一个Activity
public abstract class PackageManager {
//省掉部分代码
@SystemApi
public static final String ACTION_REQUEST_PERMISSIONS =
"android.content.pm.action.REQUEST_PERMISSIONS";
public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
if (ArrayUtils.isEmpty(permissions)) {
throw new IllegalArgumentException("permission cannot be null or empty");
}
//隐式Intent,注册了ACTION_REQUEST_PERMISSIONS的Activity能够处理此Intent
Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
intent.setPackage(getPermissionControllerPackageName());
return intent;
}
//省掉部分代码
}
PackageManager
发动了一个隐式的Intent,ACTION为android.content.pm.action.REQUEST_PERMISSIONS
,那么注册了该ACTION的即可处理此Intent,而GrantPermissionsActivity
就注册了此ACTION
<activity android:name="com.android.packageinstaller.permission.ui.GrantPermissionsActivity"
android:configChanges="keyboardHidden|screenSize"
android:excludeFromRecents="true"
android:theme="@style/GrantPermissions"
android:visibleToInstantApps="true"
android:inheritShowWhenLocked="true">
<intent-filter android:priority="1">
<!--注册了方针action-->
<action android:name="android.content.pm.action.REQUEST_PERMISSIONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
能够看到此Activity的theme设置为了GrantPermissions,而此theme的界说为
<style name="GrantPermissions"
parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<!-- The following attributes change the behavior of the dialog, hence they should not be
themed -->
<item name="android:windowIsTranslucent">true</item>
</style>
风格为对话框,没有窗口标题,透明布景,沉浸式状况栏,不便是咱们弹出的授权对话框吗
图1
再看看Activity的处理
public class GrantPermissionsActivity extends Activity
implements GrantPermissionsViewHandler.ResultListener {
//省掉部分代码
private GrantPermissionsViewHandler mViewHandler;
private String[] mRequestedPermissions;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
//省掉部分代码
//获取要请求的权限
mRequestedPermissions = getIntent().getStringArrayExtra(
PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES);
// Don't allow legacy apps to request runtime permissions.
//6.0以下不需求动态授权
if (callingPackageInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
// Returning empty arrays means a cancellation.
mRequestedPermissions = new String[0];
setResultAndFinish();
return;
}
//省掉部分代码
//依据不同的设备创立不同的Handler
if (DeviceUtils.isTelevision(this)) {
mViewHandler = new com.android.packageinstaller.permission.ui.television
.GrantPermissionsViewHandlerImpl(this,
mCallingPackage).setResultListener(this);
} else if (DeviceUtils.isWear(this)) {
mViewHandler = new GrantPermissionsWatchViewHandler(this).setResultListener(this);
} else if (DeviceUtils.isAuto(this)) {
mViewHandler = new GrantPermissionsAutoViewHandler(this, mCallingPackage, userHandle)
.setResultListener(this);
} else {
mViewHandler = new com.android.packageinstaller.permission.ui.handheld
.GrantPermissionsViewHandlerImpl(this, mCallingPackage, userHandle)
.setResultListener(this);
}
//省掉部分代码
//设置页面布局
setContentView(mViewHandler.createView());
//省掉部分代码
}
页面布局文件的创立在对应的Handler的createView()
办法傍边,由于我是在手机上测试的,所以创立的是GrantPermissionsViewHandlerImpl
public class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler,
OnClickListener {
//省掉部分代码
@Override
public View createView() {
mRootView = (ViewGroup) LayoutInflater.from(mActivity)
.inflate(R.layout.grant_permissions, null);
int h = mActivity.getResources().getDisplayMetrics().heightPixels;
mRootView.setMinimumHeight(h);
//省掉部分代码
return mRootView;
}
//省掉部分代码
}
翻开grant_permissions.xml
文件,便是图1中的布局,直接看点击答应和回绝之后的处理
public class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler,
OnClickListener {
//省掉部分代码
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.permission_allow_button:
//点击答应
if (mResultListener != null) {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS);
}
break;
case R.id.permission_allow_always_button:
//点击一直答应
if (mResultListener != null) {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS);
}
break;
case R.id.permission_allow_foreground_only_button:
//点击运行期间答应
if (mResultListener != null) {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
mResultListener.onPermissionGrantResult(mGroupName,
GRANTED_FOREGROUND_ONLY);
}
break;
case R.id.permission_deny_button:
//点击回绝
if (mResultListener != null) {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
mResultListener.onPermissionGrantResult(mGroupName, DENIED);
}
break;
case R.id.permission_deny_and_dont_ask_again_button:
//点击回绝且不再提示
if (mResultListener != null) {
view.performAccessibilityAction(
AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
mResultListener.onPermissionGrantResult(mGroupName,
DENIED_DO_NOT_ASK_AGAIN);
}
break;
//省掉部分代码
}
}
//省掉部分代码
}
无论点击什么按钮,都经过ResultListener
进行回调,并带着用户挑选的结果,GrantPermissionsActivity
完成了这个接口,看一下它的处理
public class GrantPermissionsActivity extends Activity
implements GrantPermissionsViewHandler.ResultListener {
//省掉部分代码
@Override
public void onPermissionGrantResult(String name,
@GrantPermissionsViewHandler.Result int result) {
//记载日志
logGrantPermissionActivityButtons(name, result);
GroupState foregroundGroupState = getForegroundGroupState(name);
GroupState backgroundGroupState = getBackgroundGroupState(name);
//假如设备处于锁屏状况,先免除锁屏
if (result == GRANTED_ALWAYS || result == GRANTED_FOREGROUND_ONLY
|| result == DENIED_DO_NOT_ASK_AGAIN) {
KeyguardManager kgm = getSystemService(KeyguardManager.class);
if (kgm.isDeviceLocked()) {
kgm.requestDismissKeyguard(this, new KeyguardManager.KeyguardDismissCallback() {
@Override
public void onDismissError() {
Log.e(LOG_TAG, "Cannot dismiss keyguard perm=" + name + " result="
+ result);
}
@Override
public void onDismissCancelled() {
// do nothing (i.e. stay at the current permission group)
}
@Override
public void onDismissSucceeded() {
// Now the keyguard is dismissed, hence the device is not locked
// anymore
//解锁后持续履行此办法
onPermissionGrantResult(name, result);
}
});
return;
}
}
//依据用户挑选履行对应的动作
switch (result) {
case GRANTED_ALWAYS :
if (foregroundGroupState != null) {
onPermissionGrantResultSingleState(foregroundGroupState, true, false);
}
if (backgroundGroupState != null) {
onPermissionGrantResultSingleState(backgroundGroupState, true, false);
}
break;
case GRANTED_FOREGROUND_ONLY :
if (foregroundGroupState != null) {
onPermissionGrantResultSingleState(foregroundGroupState, true, false);
}
if (backgroundGroupState != null) {
onPermissionGrantResultSingleState(backgroundGroupState, false, false);
}
break;
case DENIED :
if (foregroundGroupState != null) {
onPermissionGrantResultSingleState(foregroundGroupState, false, false);
}
if (backgroundGroupState != null) {
onPermissionGrantResultSingleState(backgroundGroupState, false, false);
}
break;
case DENIED_DO_NOT_ASK_AGAIN :
if (foregroundGroupState != null) {
onPermissionGrantResultSingleState(foregroundGroupState, false, true);
}
if (backgroundGroupState != null) {
onPermissionGrantResultSingleState(backgroundGroupState, false, true);
}
break;
}
if (!showNextPermissionGroupGrantRequest()) {
setResultAndFinish();
}
}
//省掉部分代码
}
能够看到终究都会履行onPermissionGrantResultSingleState()
private void onPermissionGrantResultSingleState(GroupState groupState, boolean granted,
boolean doNotAskAgain) {
if (groupState != null && groupState.mGroup != null
&& groupState.mState == GroupState.STATE_UNKNOWN) {
if (granted) {
//用户答应授权
groupState.mGroup.grantRuntimePermissions(doNotAskAgain,
groupState.affectedPermissions);
groupState.mState = GroupState.STATE_ALLOWED;
reportRequestResult(groupState.affectedPermissions,
PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED);
} else {
//用户回绝授权
groupState.mGroup.revokeRuntimePermissions(doNotAskAgain,
groupState.affectedPermissions);
groupState.mState = GroupState.STATE_DENIED;
reportRequestResult(groupState.affectedPermissions, doNotAskAgain
?
PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE
: PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED);
}
}
}
看看答应授权的逻辑
public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) {
boolean killApp = false;
boolean wasAllGranted = true;
//权限状况装备
// We toggle permissions only to apps that support runtime
// permissions, otherwise we toggle the app op corresponding
// to the permission if the permission is granted to the app.
for (Permission permission : mPermissions.values()) {
if (filterPermissions != null
&& !ArrayUtils.contains(filterPermissions, permission.getName())) {
continue;
}
if (!permission.isGrantingAllowed(mIsEphemeralApp, mAppSupportsRuntimePermissions)) {
// Skip unallowed permissions.
continue;
}
boolean wasGranted = permission.isGrantedIncludingAppOp();
if (mAppSupportsRuntimePermissions) {
// Do not touch permissions fixed by the system.
if (permission.isSystemFixed()) {
wasAllGranted = false;
break;
}
// Ensure the permission app op enabled before the permission grant.
if (permission.affectsAppOp() && !permission.isAppOpAllowed()) {
permission.setAppOpAllowed(true);
}
// Grant the permission if needed.
if (!permission.isGranted()) {
permission.setGranted(true);
}
// Update the permission flags.
if (!fixedByTheUser) {
// Now the apps can ask for the permission as the user
// no longer has it fixed in a denied state.
if (permission.isUserFixed() || permission.isUserSet()) {
permission.setUserFixed(false);
permission.setUserSet(false);
}
}
} else {
// Legacy apps cannot have a not granted permission but just in case.
if (!permission.isGranted()) {
continue;
}
// If the permissions has no corresponding app op, then it is a
// third-party one and we do not offer toggling of such permissions.
if (permission.affectsAppOp()) {
if (!permission.isAppOpAllowed()) {
permission.setAppOpAllowed(true);
// Legacy apps do not know that they have to retry access to a
// resource due to changes in runtime permissions (app ops in this
// case). Therefore, we restart them on app op change, so they
// can pick up the change.
killApp = true;
}
// Mark that the permission should not be be granted on upgrade
// when the app begins supporting runtime permissions.
if (permission.shouldRevokeOnUpgrade()) {
permission.setRevokeOnUpgrade(false);
}
}
// Granting a permission explicitly means the user already
// reviewed it so clear the review flag on every grant.
if (permission.isReviewRequired()) {
permission.unsetReviewRequired();
}
}
// If we newly grant background access to the fine location, double-guess the user some
// time later if this was really the right choice.
if (!wasGranted && permission.isGrantedIncludingAppOp()) {
if (permission.getName().equals(ACCESS_FINE_LOCATION)) {
Permission bgPerm = permission.getBackgroundPermission();
if (bgPerm != null) {
if (bgPerm.isGrantedIncludingAppOp()) {
mTriggerLocationAccessCheckOnPersist = true;
}
}
} else if (permission.getName().equals(ACCESS_BACKGROUND_LOCATION)) {
ArrayList<Permission> fgPerms = permission.getForegroundPermissions();
if (fgPerms != null) {
int numFgPerms = fgPerms.size();
for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) {
Permission fgPerm = fgPerms.get(fgPermNum);
if (fgPerm.getName().equals(ACCESS_FINE_LOCATION)) {
if (fgPerm.isGrantedIncludingAppOp()) {
mTriggerLocationAccessCheckOnPersist = true;
}
break;
}
}
}
}
}
}
if (!mDelayChanges) {
//这儿很重要,将授权信息耐久化保存到本地
persistChanges(false);
if (killApp) {
killApp(KILL_REASON_APP_OP_CHANGE);
}
}
return wasAllGranted;
}
授权过程便是本地数据装备的过程,最后有一个逻辑很关键,便是将授权信息进行耐久化保存,由于当咱们关机重启后,需求恢复各个app的授权信息,看看保存到哪儿了
void persistChanges(boolean mayKillBecauseOfAppOpsChange) {
int uid = mPackageInfo.applicationInfo.uid;
int numPermissions = mPermissions.size();
boolean shouldKillApp = false;
for (int i = 0; i < numPermissions; i++) {
Permission permission = mPermissions.valueAt(i);
if (!permission.isSystemFixed()) {
if (permission.isGranted()) {
mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
permission.getName(), mUserHandle);
} else {
boolean isCurrentlyGranted = mContext.checkPermission(permission.getName(), -1,
uid) == PERMISSION_GRANTED;
if (isCurrentlyGranted) {
mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
permission.getName(), mUserHandle);
}
}
}
int flags = (permission.isUserSet() ? PackageManager.FLAG_PERMISSION_USER_SET : 0)
| (permission.isUserFixed() ? PackageManager.FLAG_PERMISSION_USER_FIXED : 0)
| (permission.shouldRevokeOnUpgrade()
? PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE : 0)
| (permission.isPolicyFixed() ? PackageManager.FLAG_PERMISSION_POLICY_FIXED : 0)
| (permission.isReviewRequired()
? PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED : 0);
//更新权限标识位,这儿是去更新PMS里边当时app的权限装备
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_USER_SET
| PackageManager.FLAG_PERMISSION_USER_FIXED
| PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE
| PackageManager.FLAG_PERMISSION_POLICY_FIXED
| PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED,
flags, mUserHandle);
if (permission.affectsAppOp()) {
if (!permission.isSystemFixed()) {
// Enabling/Disabling an app op may put the app in a situation in which it has
// a handle to state it shouldn't have, so we have to kill the app. This matches
// the revoke runtime permission behavior.
if (permission.isAppOpAllowed()) {
shouldKillApp |= allowAppOp(permission, uid);
} else {
shouldKillApp |= disallowAppOp(permission, uid);
}
}
}
}
if (mayKillBecauseOfAppOpsChange && shouldKillApp) {
killApp(KILL_REASON_APP_OP_CHANGE);
}
if (mTriggerLocationAccessCheckOnPersist) {
new LocationAccessCheck(mContext, null).checkLocationAccessSoon();
mTriggerLocationAccessCheckOnPersist = false;
}
}
这儿经过AIDL,将当时授权信息发送给PMS,使得PMS中保存的当时app的授权信息得以更新
@Override
public void updatePermissionFlags(String permissionName, String packageName,
int flagMask, int flagValues, UserHandle user) {
try {
//跨进程调用,履行PackageManagerService的updatePermissionFlags()
mPM.updatePermissionFlags(permissionName, packageName, flagMask,
flagValues,
mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
看看PackageManagerService的处理
@Override
public void updatePermissionFlags(String permName, String packageName, int flagMask,
int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
int callingUid = getCallingUid();
boolean overridePolicy = false;
if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) {
long callingIdentity = Binder.clearCallingIdentity();
try {
if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0) {
if (checkAdjustPolicyFlagPermission) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
"Need " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY
+ " to change policy flags");
} else if (!hasTargetSdkInUidLowerThan(callingUid, Build.VERSION_CODES.Q)) {
throw new IllegalArgumentException(
Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " needs "
+ " to be checked for packages targeting "
+ Build.VERSION_CODES.Q + " or later when changing policy "
+ "flags");
}
overridePolicy = true;
}
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
}
//经过PermissionManagerService操作
mPermissionManager.updatePermissionFlags(
permName, packageName, flagMask, flagValues, callingUid, userId,
overridePolicy, mPermissionCallback);
}
终究更新的是PermissionManagerService
傍边的数据
private void updatePermissionFlags(String permName, String packageName, int flagMask,
int flagValues, int callingUid, int userId, boolean overridePolicy,
PermissionCallback callback) {
//省掉部分代码
//先获取PackageParser.Package
final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
//省掉部分代码
//更新Package的mExtras
final PackageSetting ps = (PackageSetting) pkg.mExtras;
final PermissionsState permissionsState = ps.getPermissionsState();
final boolean hadState =
permissionsState.getRuntimePermissionState(permName, userId) != null;
final boolean permissionUpdated =
permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues);
if (permissionUpdated && bp.isRuntime()) {
notifyRuntimePermissionStateChanged(packageName, userId);
}
if (permissionUpdated && callback != null) {
// Install and runtime permissions are stored in different places,
// so figure out what permission changed and persist the change.
if (permissionsState.getInstallPermissionState(permName) != null) {
//通知安装权限更新,便是不需求动态授权的权限
callback.onInstallPermissionUpdated();
} else if (permissionsState.getRuntimePermissionState(permName, userId) != null
|| hadState) {
//通知动态权限状况更新
callback.onPermissionUpdated(new int[] { userId }, false);
}
}
}
能够看到,终究更新的是PackageParser.Package
的mExtras
字段,上面咱们剖析知道,在查看权限时,也是读取的PackageParser.Package
的mExtras
字段,这儿就跟前面的逻辑相照应了,更新完之后,经过callback进行回调,履行耐久化存储
@Override
public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
synchronized (mPackages) {
for (int userId : updatedUserIds) {
mSettings.writeRuntimePermissionsForUserLPr(userId, sync);
}
}
}
public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
if (sync) {
mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
} else {
mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
}
}
private void writePermissionsSync(int userId) {
//界说耐久化保存途径
AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId),
"package-perms-" + userId);
//省掉部分代码
FileOutputStream out = null;
try {
//省掉部分代码
//保存到本地
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);
}
}
//文件名
private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
//获取途径
private File getUserRuntimePermissionsFile(int userId) {
// TODO: Implement a cleaner solution when adding tests.
// This instead of Environment.getUserSystemDirectory(userId) to support testing.
File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
File file = new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME);
Log.d("jasonwan", "getUserRuntimePermissionsFile: file="+file.getAbsolutePath());
return file;
}
经过log打印得知,权限文件途径位于/data/system/users/0/runtime-permissions.xml
,咱们从设备中导出此文件翻开看看长啥样
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<runtime-permissions version="8" fingerprint="qti/trinket/trinket:10/QKQ1.200816.002/2211:userdebug/test-keys">
<pkg name="com.android.externalstorage">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
</pkg>
<pkg name="com.android.companiondevicemanager">
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="false" flags="b0" />
<item name="android.permission.ACCESS_BACKGROUND_LOCATION" granted="true" flags="3030" />
</pkg>
<pkg name="com.android.quicksearchbox">
<item name="android.permission.READ_CONTACTS" granted="false" flags="300" />
</pkg>
<pkg name="com.android.soundrecorder">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="false" flags="2380" />
<item name="android.permission.READ_PHONE_STATE" granted="false" flags="300" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="false" flags="2300" />
<item name="android.permission.RECORD_AUDIO" granted="true" flags="320" />
<item name="android.permission.ACCESS_MEDIA_LOCATION" granted="false" flags="380" />
</pkg>
<pkg name="com.android.contacts">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="false" flags="2300" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="320" />
<item name="android.permission.CALL_PHONE" granted="true" flags="320" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="320" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="320" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="320" />
<item name="android.permission.ACCESS_MEDIA_LOCATION" granted="false" flags="380" />
</pkg>
<pkg name="com.android.mms">
<item name="android.permission.READ_SMS" granted="true" flags="3320" />
<item name="android.permission.RECEIVE_WAP_PUSH" granted="true" flags="3320" />
<item name="android.permission.RECEIVE_MMS" granted="true" flags="3320" />
<item name="android.permission.RECEIVE_SMS" granted="true" flags="3320" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="33a0" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="320" />
<item name="android.permission.SEND_SMS" granted="true" flags="3320" />
<item name="android.permission.CALL_PHONE" granted="true" flags="320" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="320" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3320" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="320" />
<item name="android.permission.ACCESS_MEDIA_LOCATION" granted="true" flags="3a0" />
</pkg>
<pkg name="com.android.launcher3">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="false" flags="2100" />
<item name="android.permission.READ_PHONE_STATE" granted="false" flags="100" />
<item name="android.permission.CALL_PHONE" granted="false" flags="100" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="false" flags="2100" />
</pkg>
<pkg name="com.android.settings.intelligence">
<item name="android.permission.READ_PHONE_STATE" granted="false" flags="100" />
</pkg>
<pkg name="com.android.calendar">
<item name="android.permission.READ_CALENDAR" granted="true" flags="320" />
<item name="android.permission.WRITE_CALENDAR" granted="true" flags="320" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="320" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="320" />
</pkg>
<pkg name="com.android.sharedstoragebackup">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30b0" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
</pkg>
<pkg name="com.android.printspooler">
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
</pkg>
<!-- 测试Demo-->
<pkg name="com.jason.nodetest">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="b00" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="b00" />
</pkg>
<pkg name="com.android.email">
<item name="android.permission.READ_CALENDAR" granted="true" flags="320" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="false" flags="2380" />
<item name="android.permission.READ_PHONE_STATE" granted="false" flags="300" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="320" />
<item name="android.permission.WRITE_CALENDAR" granted="true" flags="320" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="320" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="false" flags="2300" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="320" />
<item name="android.permission.ACCESS_MEDIA_LOCATION" granted="false" flags="380" />
</pkg>
<pkg name="com.android.music">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3320" />
<item name="android.permission.READ_PHONE_STATE" granted="false" flags="300" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3320" />
<item name="android.permission.ACCESS_MEDIA_LOCATION" granted="true" flags="3a0" />
</pkg>
<shared-user name="android.media">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
</shared-user>
<shared-user name="android.uid.systemui">
<item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
<item name="android.permission.CAMERA" granted="true" flags="30" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
<item name="android.permission.RECORD_AUDIO" granted="true" flags="30" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
<shared-user name="android.uid.nfc">
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30b0" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
<shared-user name="android.uid.bluetooth">
<item name="android.permission.READ_SMS" granted="true" flags="3030" />
<item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
<item name="com.android.email.permission.READ_ATTACHMENT" granted="true" flags="1030" />
<item name="android.permission.RECEIVE_SMS" granted="true" flags="3030" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="30" />
<item name="android.permission.SEND_SMS" granted="true" flags="3030" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="1030" />
<item name="android.permission.WRITE_CALL_LOG" granted="true" flags="3030" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="1030" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="1030" />
</shared-user>
<shared-user name="android.uid.shared">
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="30" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
<shared-user name="android.uid.system">
<item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="1030" />
<item name="android.permission.RECEIVE_WAP_PUSH" granted="true" flags="3030" />
<item name="android.permission.RECEIVE_SMS" granted="true" flags="3030" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="false" flags="10b0" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="1030" />
<item name="android.permission.SEND_SMS" granted="true" flags="3030" />
<item name="android.permission.CALL_PHONE" granted="true" flags="1330" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="1330" />
<item name="android.permission.CAMERA" granted="true" flags="1330" />
<item name="android.permission.WRITE_CALL_LOG" granted="true" flags="3030" />
<item name="android.permission.PROCESS_OUTGOING_CALLS" granted="true" flags="3030" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.RECORD_AUDIO" granted="true" flags="1330" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="1330" />
<item name="android.permission.ACCESS_BACKGROUND_LOCATION" granted="true" flags="3030" />
<item name="android.permission.ACCESS_MEDIA_LOCATION" granted="true" flags="1030" />
</shared-user>
<shared-user name="android.uid.phone">
<item name="android.permission.READ_SMS" granted="true" flags="3030" />
<item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
<item name="android.permission.RECEIVE_SMS" granted="true" flags="3030" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="1030" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="30" />
<item name="android.permission.SEND_SMS" granted="true" flags="3030" />
<item name="android.permission.CALL_PHONE" granted="true" flags="30" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
<item name="android.permission.CAMERA" granted="true" flags="1030" />
<item name="android.permission.WRITE_CALL_LOG" granted="true" flags="3030" />
<item name="android.permission.USE_SIP" granted="true" flags="1030" />
<item name="android.permission.PROCESS_OUTGOING_CALLS" granted="true" flags="3030" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="1030" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.RECORD_AUDIO" granted="true" flags="1030" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
<item name="android.permission.ACCESS_BACKGROUND_LOCATION" granted="true" flags="3030" />
<item name="com.android.voicemail.permission.ADD_VOICEMAIL" granted="true" flags="1030" />
</shared-user>
<shared-user name="android.uid.shell">
<item name="android.permission.READ_SMS" granted="true" flags="3030" />
<item name="android.permission.READ_CALENDAR" granted="true" flags="30" />
<item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="30" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.ACCESS_COARSE_LOCATION" granted="false" flags="30" />
<item name="android.permission.READ_PHONE_STATE" granted="true" flags="30" />
<item name="android.permission.SEND_SMS" granted="true" flags="3030" />
<item name="android.permission.CALL_PHONE" granted="true" flags="30" />
<item name="android.permission.WRITE_CONTACTS" granted="true" flags="30" />
<item name="android.permission.WRITE_CALENDAR" granted="true" flags="30" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="30" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3030" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
<shared-user name="android.uid.calendar">
<item name="android.permission.READ_CALENDAR" granted="true" flags="30" />
<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="30a0" />
<item name="android.permission.WRITE_CALENDAR" granted="true" flags="30" />
<item name="android.permission.GET_ACCOUNTS" granted="true" flags="20" />
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="3020" />
</shared-user>
<shared-user name="com.android.emergency.uid">
<item name="android.permission.READ_CALL_LOG" granted="true" flags="3030" />
<item name="android.permission.CALL_PHONE" granted="true" flags="30" />
<item name="android.permission.READ_CONTACTS" granted="true" flags="30" />
</shared-user>
</runtime-permissions>
能够看到此文件保存便是各个app的动态权限授权状况,安装权限不在此文件中,咱们的测试demo包名为com.jason.nodetest
,能够看到咱们只答应读存储卡权限后,读写权限均为已授权。
相同,当体系重启后,PackageManagerService会初始化并发动,初始化时会从UserServiceManager
中获取读取的权限数据
public class PackageManagerService extends IPackageManager.Stub
implements PackageSender {
//省掉部分代码
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
//省掉部分代码
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings");
//UserManager创立用户时会去读取用户装备文件,其中就包含runtime-permissions.xml文件
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
//省掉部分代码
}
//省掉部分代码
}
boolean readLPw(@NonNull List<UserInfo> users) {
//省掉部分代码
for (UserInfo user : users) {
//读取一切用户装备信息
mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id);
}
//省掉部分代码
}
@GuardedBy("Settings.this.mLock")
public void readStateForUserSyncLPr(int userId) {
//获取runtime-permissions.xml文件
File permissionsFile = getUserRuntimePermissionsFile(userId);
if (!permissionsFile.exists()) {
return;
}
FileInputStream in;
try {
in = new AtomicFile(permissionsFile).openRead();
} catch (FileNotFoundException fnfe) {
Slog.i(PackageManagerService.TAG, "No permissions state");
return;
}
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in, null);
//解析runtime-permissions.xml文件
parseRuntimePermissionsLPr(parser, userId);
} catch (XmlPullParserException | IOException e) {
throw new IllegalStateException("Failed parsing permissions file: "
+ permissionsFile , e);
} finally {
IoUtils.closeQuietly(in);
}
}
@GuardedBy("Settings.this.mLock")
private void parseRuntimePermissionsLPr(XmlPullParser parser, int userId)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
switch (parser.getName()) {
case TAG_RUNTIME_PERMISSIONS: {
// If the permisions settings file exists but the version is not set this is
// an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION
int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION,
UPGRADE_VERSION);
mVersions.put(userId, version);
String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT);
mFingerprints.put(userId, fingerprint);
final boolean defaultsGranted = Build.FINGERPRINT.equals(fingerprint);
mDefaultPermissionsGranted.put(userId, defaultsGranted);
} break;
case TAG_PACKAGE: {
String name = parser.getAttributeValue(null, ATTR_NAME);
PackageSetting ps = mPackages.get(name);
if (ps == null) {
Slog.w(PackageManagerService.TAG, "Unknown package:" + name);
XmlUtils.skipCurrentTag(parser);
continue;
}
parsePermissionsLPr(parser, ps.getPermissionsState(), userId);
} break;
case TAG_SHARED_USER: {
//读取shared-user标签,拿到包名
String name = parser.getAttributeValue(null, ATTR_NAME);
SharedUserSetting sus = mSharedUsers.get(name);
if (sus == null) {
Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name);
XmlUtils.skipCurrentTag(parser);
continue;
}
//解析shared-user下的一切item权限
parsePermissionsLPr(parser, sus.getPermissionsState(), userId);
} break;
}
}
}
private void parsePermissionsLPr(XmlPullParser parser, PermissionsState permissionsState,
int userId) throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
switch (parser.getName()) {
case TAG_ITEM: {
//读取权限称号
String name = parser.getAttributeValue(null, ATTR_NAME);
BasePermission bp = mPermissions.getPermission(name);
if (bp == null) {
Slog.w(PackageManagerService.TAG, "Unknown permission:" + name);
XmlUtils.skipCurrentTag(parser);
continue;
}
//读取权限授权状况
String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED);
final boolean granted = grantedStr == null
|| Boolean.parseBoolean(grantedStr);
//读取权限的flag
String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS);
final int flags = (flagsStr != null)
? Integer.parseInt(flagsStr, 16) : 0;
//给权限赋值
if (granted) {
permissionsState.grantRuntimePermission(bp, userId);
permissionsState.updatePermissionFlags(bp, userId,
PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
} else {
permissionsState.updatePermissionFlags(bp, userId,
PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
}
} break;
}
}
能够看到,从runtime-permissions.xml
文件中读取的授权信息终究赋值给了PermissionsState
,而咱们在查看权限时也是从PermissionState
中获取的权限授权状况,这儿跟前面形成了闭环。
总结
以上便是Android 10动态授权的整个流程,简单总结下便是
1、Android发动,PackageManagerService
发动,扫描APK获取一切权限
2、读取runtime-permissions.xml
文件,获取动态权限授权状况,并将他赋值给PermissionState
3、用户查看权限,从PermissionState
中获取方针权限的授权状况,并返给app
4、用户请求权限,依据用户的挑选,设置PermissionState
中对应权限的状况,并耐久化存储到runtime-permissions.xml
文件中