Android 检查权限源码分析

检查权限时序图

检查权限一般使用 androidx 包下的 ContextCompat#checkSelfPermission() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package androidx.core.content;

public class ContextCompat {
/**
* 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)
*/
public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}

return context.checkPermission(permission, Process.myPid(), Process.myUid());
}
}

源码基于 sdk-31(Android 12/S)

1
2
3
4
5
6
7
8
9
10
11
12
13
// ContextImpl.java

public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
if (mParams.isRenouncedPermission(permission)
&& pid == android.os.Process.myPid() && uid == android.os.Process.myUid()) {
Log.v(TAG, "Treating renounced permission " + permission + " as denied");
return PERMISSION_DENIED;
}
return PermissionManager.checkPermission(permission, pid, uid);
}
  1. 如果权限是否在废弃列表中,拒绝权限;
  2. 调用 PermissionManager 检查权限;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@SystemApi
@SystemService(Context.PERMISSION_SERVICE)
public final class PermissionManager {
private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache =
new PropertyInvalidatedCache<PermissionQuery, Integer>(
2048, CACHE_KEY_PACKAGE_INFO, "checkPermission") {
@Override
protected Integer recompute(PermissionQuery query) {
return checkPermissionUncached(query.permission, query.pid, query.uid);
}
};

/** @hide */
public static int checkPermission(String permission, int pid, int uid) {
return sPermissionCache.query(new PermissionQuery(permission, pid, uid));
}

private static int checkPermissionUncached(String permission, int pid, int uid) {
final IActivityManager am = ActivityManager.getService();
return am.checkPermission(permission, pid, uid);
}
}
  1. 使用 PropertyInvalidatedCache 保存权限缓存;
  2. 如果没有命中缓存,通过 AMS 检查权限。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ActivityManagerService extends IActivityManager.Stub {
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
return PackageManager.PERMISSION_DENIED;
}
//
return checkComponentPermission(permission, pid, uid, -1, true);
}

public static int checkComponentPermission(String permission, int pid, int uid,
int owningUid, boolean exported) {
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
// ...
return ActivityManager.checkComponentPermission(permission, uid,
owningUid, exported);
}
}
  1. 调用了 ActivityManager#checkComponentPermission() 方法,并设置 owningUid = -1,exported = true;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@SystemService(Context.ACTIVITY_SERVICE)
public class ActivityManager {
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
final int appId = UserHandle.getAppId(uid);
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.
if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
return PackageManager.PERMISSION_GRANTED;
}
// If the target is not exported, then nobody else can get to it.
if (!exported) {
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
return PackageManager.PERMISSION_GRANTED;
}
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
}
}
  1. 如果是 Root、System 或同一进程返回 PERMISSION_GRANTED;
  2. 孤立进程、权限为空和不允许导出返回 PERMISSION_DENIED;
  3. 最后通过 PMS 检查权限。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class PackageManagerService extends IPackageManager.Stub {
private final PermissionManagerServiceInternal mPermissionManager;

@Override
public int checkUidPermission(String permName, int uid) {
return mComputer.checkUidPermission(permName, uid);
}

protected static class ComputerEngine implements Computer {
public final int checkUidPermission(String permName, int uid) {
return mPermissionManager.checkUidPermission(uid, permName);
}
}
}
  1. 又通过 PermissionManagerService 检查权限;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public class PermissionManagerService extends IPermissionManager.Stub {
private class PermissionManagerServiceInternalImpl implements PermissionManagerServiceInternal {
@Override
public int checkUidPermission(int uid, @NonNull String permissionName) {
return PermissionManagerService.this.checkUidPermission(uid, permissionName);
}
}

private int checkUidPermission(int uid, String permName) {
// Not using Objects.requireNonNull() here for compatibility reasons.
if (permName == null) {
return PackageManager.PERMISSION_DENIED;
}
final int userId = UserHandle.getUserId(uid);
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
}

final CheckPermissionDelegate checkPermissionDelegate;
synchronized (mLock) {
checkPermissionDelegate = mCheckPermissionDelegate;
}
if (checkPermissionDelegate == null) {
return checkUidPermissionImpl(uid, permName);
}
return checkPermissionDelegate.checkUidPermission(uid, permName,
this::checkUidPermissionImpl);
}

private int checkUidPermissionInternal(@Nullable AndroidPackage pkg, int uid,
@NonNull String permissionName) {
if (pkg != null) {
final int userId = UserHandle.getUserId(uid);
return checkPermissionInternal(pkg, false, permissionName, userId);
}

// ...

return PackageManager.PERMISSION_DENIED;
}

private int checkPermissionInternal(@NonNull AndroidPackage pkg, boolean isPackageExplicit,
@NonNull String permissionName, @UserIdInt int userId) {
final int callingUid = getCallingUid();
if (isPackageExplicit || pkg.getSharedUserId() == null) {
if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
return PackageManager.PERMISSION_DENIED;
}
} else {
if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
return PackageManager.PERMISSION_DENIED;
}
}

final int uid = UserHandle.getUid(userId, pkg.getUid());
final boolean isInstantApp = mPackageManagerInt.getInstantAppPackageName(uid) != null;

synchronized (mLock) {
final UidPermissionState uidState = getUidStateLocked(pkg, userId);
if (uidState == null) {
Slog.e(TAG, "Missing permissions state for " + pkg.getPackageName() + " and user "
+ userId);
return PackageManager.PERMISSION_DENIED;
}

if (checkSinglePermissionInternalLocked(uidState, permissionName, isInstantApp)) {
return PackageManager.PERMISSION_GRANTED;
}

final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
if (fullerPermissionName != null && checkSinglePermissionInternalLocked(uidState,
fullerPermissionName, isInstantApp)) {
return PackageManager.PERMISSION_GRANTED;
}
}

return PackageManager.PERMISSION_DENIED;
}

private boolean checkSinglePermissionInternalLocked(@NonNull UidPermissionState uidState,
@NonNull String permissionName, boolean isInstantApp) {
if (!uidState.isPermissionGranted(permissionName)) {
return false;
}

if (isInstantApp) {
final Permission permission = mRegistry.getPermission(permissionName);
return permission != null && permission.isInstant();
}

return true;
}
}
  1. 最后权限是通过 UidPermissionState 来判断;
  2. PERMISSION_GRANTED = 0,PERMISSION_DENIED = -1;
1
2
3
4
5
6
7
8
9
/**
* Permission state for a UID.
*/
public final class UidPermissionState {
public boolean isPermissionGranted(@NonNull String name) {
final PermissionState permissionState = getPermissionState(name);
return permissionState != null && permissionState.isGranted();
}
}