Android 中的动态权限

Dynamic Permissions in Android

我想知道第三方应用是否可以动态添加系统权限。根据 this book,可以通过使用 public addPermission() API;但是,我收到一个 SecurityException,上面写着 "java.lang.SecurityException: You either need MANAGE_USERS or CREATE_USERS permission to: query users"。我只是想确保它真的是因为系统不允许,而不是因为我在代码中搞砸了。如果是这种情况,则不允许对未使用系统证书签名的第三方应用程序动态添加权限,如果有人能解释一下这种选择背后的原因,那就太好了。

以下是我如何以编程方式添加权限:

public void addDynamicPermission() {
    PermissionInfo pi = new PermissionInfo();
    pi.name = "com.somedomain.permission.MY_PERMISSION";
    pi.labelRes = R.string.permission_label;
    pi.protectionLevel = PermissionInfo.PROTECTION_DANGEROUS;
    final PackageManager packageManager = getApplicationContext().getPackageManager();
    packageManager.addPermission(pi);
}

这是我的清单文件中的内容: <permission-tree android:name="com.somedomain.permission" />

这是异常的完整 java 堆栈:

FATAL EXCEPTION: main
Process: com.example.myapp, PID: 11824
java.lang.SecurityException: You either need MANAGE_USERS or CREATE_USERS permission to: query users
at android.os.Parcel.readException(Parcel.java:1684)
at android.os.Parcel.readException(Parcel.java:1637)
at android.content.pm.IPackageManager$Stub$Proxy.addPermission(IPackageManager.java:2870)
at android.app.ApplicationPackageManager.addPermission(ApplicationPackageManager.java:535)
at com.example.myapp.MainActivity.addDynamicPermission(MainActivity.java:183)
at com.example.myapp.MainActivity.onClick(MainActivity.java:64)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

非常感谢!

TL;DR:这本书已经过时了,比 Lollipop 更新的 Android 版本确实需要 MANAGE_USERSCREATE_USERS,两者都有 protectionLevel ,共 3 个(signatureOrSystem)。

更长的答案:

不久前,在 KitKat 时代,我写了一些与您类似的测试代码,我记得它运行良好。那是几年前的事了。我刚刚在当前的 Nougat (7.0) 环境中启动了那个旧应用程序,结果出现了与您所看到的完全相同的异常。出于好奇,我重新安装了 KitKat (4.4.4)、Lollipop (5.1) 和 Marshmallow (6.0) 实例,并在每个实例上尝试了该应用程序。

对于 4.4.4 和 5.1,一切正常。我通过 运行 代码验证了这一点,然后检查自定义权限是否存在,如下所示:

% adb shell dumpsys package packagename | grep -i com.example
...
Permission [com.example.permission.TEST_PERMISSION] (79c4d6d):
sourcePackage=com.example.myapplication
perm=Permission{2c725da2 com.example.permission.TEST_PERMISSION}
...

但是,在 6.0 和 7.0 上,我遇到了安全异常。快速检查 androidxref.com 表明异常来自 UserManagerService 中的 getPrimaryUsergetUsers 方法。

getPrimaryUsers 在 4.4.4 或 5.1 中不存在,并且 getUsers 一直受到 checkManageOrCreateUsersPermission 的保护。因此,我认为可以合理地假设 addPermission 链从 6.0 开始被修改以出于某种原因获取用户列表。所以 addPermission 不需要 MANAGE_USERSCREATE_USERS,但它现在调用的方法需要。

这个额外的访问控制检查是否有意以及背后的原因是我无法回答的问题。