这取决于 Android 版本。原因是从某些 Android 版本开始,Google 注意到(或只是允许)OEM 可以更改哪个权限属于哪个权限组。根据谷歌在问题跟踪器上告诉我的内容,这至少发生在一些中国 OEM 身上(这不是他们第一次破坏行为,如 here 所示)。他们甚至可以在对操作系统进行简单更新之间进行更改。
那么,这就是你今天所拥有的:
- 普通的 API(和
./adb shell pm list permissions -s 的 adb 命令)将无法正常工作。它将提供大量权限
进入“未定义”组。原因是谷歌说它可能是
因设备和 OEM 不同而不同
- 您可以查看这些版本的 Android 源代码,并希望大多数设备都使用那里的源代码。以前是here,但链接是
现在死了。我想this one可以给你同样的信息
虽然(但您需要检查它使用的是哪个 Android 版本
为)。
- 另一种处理方法是制作您自己的示例 POC 来检查每个权限 - 它属于哪个权限组。您将通过在清单中声明所有权限(从下面的代码中获取)来完成此操作,然后请求一堆权限。如果你得到一个对话框,这意味着你选择的属于一个组,你可以继续测试更多的权限,看看它们是否也属于。如果不是,则其中至少有一个属于另一个组。
要通过仅在系统中和/或 Android 本身中的权限进行过滤,您可以使用权限的包名称必须以“android”开头或权限组名称应以“开头”的条件android.permission 组。”或者权限的保护级别是 PermissionInfo.PROTECTION_SIGNATURE 。这取决于您希望过滤的内容。
所以,一个简单的函数可以列出所有 Android 版本:
enum class PermissionGroup constructor(@param:Permission @field:Permission val permissions: Array<String>) {
//based on https://developer.android.com/reference/android/Manifest.permission_group.html, https://developer.android.com/guide/topics/permissions/requesting.html https://developer.android.com/reference/android/Manifest.permission
// get all permissions and groups here: https://stackoverflow.com/a/51156191/878126 https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
CALENDAR(arrayOf(permission.READ_CALENDAR, permission.WRITE_CALENDAR)),
CAMERA(arrayOf(permission.CAMERA)),
CONTACTS(arrayOf(permission.READ_CONTACTS, permission.WRITE_CONTACTS, permission.GET_ACCOUNTS)),
LOCATION(sequenceOf(permission.ACCESS_COARSE_LOCATION, permission.ACCESS_FINE_LOCATION, if (VERSION.SDK_INT >= VERSION_CODES.Q) permission.ACCESS_BACKGROUND_LOCATION else null)
.filterNotNull().asIterable().toList().toTypedArray()),
MICROPHONE(arrayOf(permission.RECORD_AUDIO, "android.permission.RECORD_BACKGROUND_AUDIO")),
PHONE(sequenceOf(permission.READ_PHONE_STATE, if (VERSION.SDK_INT >= VERSION_CODES.P) permission.ACCEPT_HANDOVER else null,
permission.CALL_PHONE, permission.ADD_VOICEMAIL, permission.USE_SIP,
if (VERSION.SDK_INT >= VERSION_CODES.O) permission.ANSWER_PHONE_CALLS else null, if (VERSION.SDK_INT < VERSION_CODES.P) permission.READ_CALL_LOG else null,
if (VERSION.SDK_INT < VERSION_CODES.P) permission.WRITE_CALL_LOG else null, if (VERSION.SDK_INT < VERSION_CODES.P) permission.PROCESS_OUTGOING_CALLS else null,
if (VERSION.SDK_INT >= VERSION_CODES.O) permission.READ_PHONE_NUMBERS else null).filterNotNull().asIterable().toList().toTypedArray()),
SENSORS(sequenceOf(if (VERSION.SDK_INT >= VERSION_CODES.KITKAT_WATCH) permission.BODY_SENSORS else null,
if (VERSION.SDK_INT >= VERSION_CODES.M && VERSION.SDK_INT < VERSION_CODES.P) permission.USE_FINGERPRINT else null, if (VERSION.SDK_INT >= VERSION_CODES.P) permission.USE_BIOMETRIC else null)
.filterNotNull().asIterable().toList().toTypedArray()),
SMS(sequenceOf(permission.SEND_SMS, permission.RECEIVE_SMS, permission.READ_SMS, permission.RECEIVE_WAP_PUSH, permission.RECEIVE_MMS,"android.permission.READ_CELL_BROADCASTS")
.filterNotNull().asIterable().toList().toTypedArray()),
STORAGE(sequenceOf(permission.READ_EXTERNAL_STORAGE, permission.WRITE_EXTERNAL_STORAGE, if (VERSION.SDK_INT >= VERSION_CODES.Q) permission.ACCESS_MEDIA_LOCATION else null)
.filterNotNull().asIterable().toList().toTypedArray()),
CALL_LOG(if (VERSION.SDK_INT >= VERSION_CODES.P)
arrayOf(permission.READ_CALL_LOG, permission.WRITE_CALL_LOG, permission.PROCESS_OUTGOING_CALLS)
else emptyArray()),
ACTIVITY_RECOGNITION(if (VERSION.SDK_INT >= VERSION_CODES.Q) arrayOf(permission.ACTIVITY_RECOGNITION) else emptyArray()),
NEARBY_DEVICES(if (VERSION.SDK_INT >= VERSION_CODES.S) arrayOf(permission.BLUETOOTH_CONNECT, permission.BLUETOOTH_ADVERTISE, permission.UWB_RANGING, permission.BLUETOOTH_SCAN) else emptyArray())
;
@TargetApi(VERSION_CODES.S)
@StringDef(permission.READ_CALENDAR, permission.WRITE_CALENDAR, permission.CAMERA, permission.READ_CONTACTS, permission.WRITE_CONTACTS,
permission.GET_ACCOUNTS, permission.ACCEPT_HANDOVER, permission.ACCESS_COARSE_LOCATION, permission.ACCESS_FINE_LOCATION, permission.RECORD_AUDIO,
permission.USE_BIOMETRIC, permission.READ_PHONE_STATE, permission.CALL_PHONE, permission.READ_CALL_LOG, permission.WRITE_CALL_LOG, permission.ADD_VOICEMAIL,
permission.USE_SIP, permission.PROCESS_OUTGOING_CALLS, permission.BODY_SENSORS, permission.SEND_SMS, permission.RECEIVE_SMS, permission.READ_SMS, permission.RECEIVE_WAP_PUSH,
permission.RECEIVE_MMS, permission.READ_EXTERNAL_STORAGE, permission.WRITE_EXTERNAL_STORAGE, permission.ANSWER_PHONE_CALLS, permission.ACTIVITY_RECOGNITION,
permission.ACCESS_BACKGROUND_LOCATION, permission.ACCESS_MEDIA_LOCATION, "android.permission.RECORD_BACKGROUND_AUDIO",
permission.BLUETOOTH_CONNECT, permission.BLUETOOTH_ADVERTISE, permission.UWB_RANGING, permission.BLUETOOTH_SCAN,"android.permission.READ_CELL_BROADCASTS"
)
@Retention(AnnotationRetention.SOURCE)
annotation class Permission
}
然后找到它们:
fun checkPermissions() {
var permissionsCount = 0
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val permissionGroups = packageManager.getAllPermissionGroups(0)
var permissionsGroupsLeft = permissionGroups.size
permissionGroups.forEach { permissionGroup: PermissionGroupInfo ->
val permissionGroupName = permissionGroup.name
if (!permissionGroupName.startsWith("android.permission-group.")) {
if (--permissionsGroupsLeft == 0) {
Log.d("AppLog", "total permissions (of all permissions groups) count:$permissionsCount")
}
return@forEach
}
packageManager.getPlatformPermissionsForGroup(permissionGroupName, mainExecutor) { groupPermissions ->
if (groupPermissions.isNotEmpty()) {
Log.d("AppLog", "permissionGroup:$permissionGroupName")
groupPermissions.forEach { permissionName ->
Log.d("AppLog", "\t\t$permissionName")
++permissionsCount
}
}
if (--permissionsGroupsLeft == 0) {
Log.d("AppLog", "total permissions (of all permissions groups) count:$permissionsCount")
}
}
}
return
}
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
Log.d("AppLog", "cannot use API to query permissions, so guessing it is similar to what we have found about it:")
PermissionGroup.values().forEach { permissionGroup ->
val permissions = permissionGroup.permissions
if (permissions.isEmpty())
return@forEach
Log.d("AppLog", "permissionGroup:${permissionGroup.name}")
permissions.forEach { permissionName ->
Log.d("AppLog", "\t\t${permissionName}")
++permissionsCount
}
}
}
else -> {
val allPermissionGroups = packageManager.getAllPermissionGroups(0)
allPermissionGroups.forEach { permissionGroup ->
val permissionGroupName = permissionGroup.name
if (!permissionGroupName.startsWith("android.permission-group."))
return@forEach
val groupPermissions = packageManager.queryPermissionsByGroup(permissionGroupName, 0)
if (groupPermissions.isEmpty())
return@forEach
Log.d("AppLog", "permissionGroup:$permissionGroupName")
for (permission in groupPermissions) {
val permissionName = permission.name
Log.d("AppLog", "\t\t${permissionName}")
++permissionsCount
}
}
}
}
Log.d("AppLog", "total permissions (of all permissions groups) count:$permissionsCount")
}