我无法为我希望以受控方式提供敏感数据的应用授予"反向权限".
我的应用程序是一个时间跟踪器,因为时间跟踪日志可以被视为个人信息,我已经创建了访问它的权限并为其分配了android.permission-group.PERSONAL_INFO权限组.
要从手机导出时间日志,我添加了将日志作为电子邮件附件发送的功能.附件由受我新添加的权限保护的内容提供商生成.我发送电子邮件的代码如下所示:
String email = "someone@example.com";
Uri uri = TimeLog.CSVAttachment.CONTENT_URI;
Intent i = new Intent(Intent.ACTION_SEND, uri);
i.setType("text/csv");
i.putExtra(Intent.EXTRA_EMAIL, new String[]{email});
i.putExtra(Intent.EXTRA_SUBJECT, "Time log");
i.putExtra(Intent.EXTRA_TEXT, "Hello World!");
i.putExtra(Intent.EXTRA_STREAM, uri);
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(i);
Run Code Online (Sandbox Code Playgroud)
在我的HTC手机上运行时,我会在Gmail和HTC邮件之间进行弹出式选择.选择Gmail,我在Gmail应用中遇到以下异常:
ERROR/AndroidRuntime(8169): Caused by: java.lang.SecurityException:
Permission Denial: reading com.mycompany.timelog.TimeLog uri
content://com.mycompany.timelog/csv_attachment from pid=8169,
uid=10035 requires com.mycompany.timelog.permission.READ_TIME_LOG
Run Code Online (Sandbox Code Playgroud)
我确实android:grantUriPermissions="true"设置了我的提供商,但这没有帮助.我有一个关于为什么会这样的理论.我曾预计FLAG_GRANT_READ_URI_PERMISSION会授予Gmail访问我的内容提供商的权利,但我认为真正发生的是此权限授予com.android.internal.app.ResolverActivity,因为Intent和Android创建了多个匹配项用于向用户显示选择的包装器活动.
所以,我尝试将其硬编码到我的应用程序中仅用于测试:
grantUriPermission("com.google.android.gm", uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION);
Run Code Online (Sandbox Code Playgroud)
这允许Gmail正确显示电子邮件,我可以按"发送".不幸的是,在GMail关闭后,我在com.google.process.gapps中遇到了这个例外:
ERROR/AndroidRuntime(7617):java.lang.SecurityException:Permission Denial:从pid = 7617读取com.mycompany.timelog.TimeLog uri内容://com.mycompany.timelog/csv_attachment,uid = 10011要求 com.mycompany.timelog.permission.READ_TIME_LOG
请注意,这来自不同的PID和UID.这是因为对openAssetFile的实际调用是从属于不同包的某个同步提供程序组件(com.google.android.googleapps?)发生的.
虽然我有一些希望最终找到一种方法来向我的ACTION_SEND意图的最终接收者授予权限,但是对openAssetFile的调用是从一些完全不同且实际上不相关的包发生的事实让我感到困惑的是权限授予应该如何工作.
所以最终我的问题是,鉴于日志是敏感数据,我如何允许它作为附件通过电子邮件发送,同时尊重用户的隐私(例如,不使附件世界可读)?
小智 4
亲爱的来自未来的人们,
似乎谷歌本身也以另一种方式解决了这个问题,这是我在尝试解决同样的问题时偶然发现的。
如果你看看com.android.contacts.detail.ContactLoaderFragment你在方法中发现private Uri getPreAuthorizedUri(Uri uri):
mContext.getContentResolver().call(
ContactsContract.AUTHORITY_URI,
ContactsContract.Authorization.AUTHORIZATION_METHOD,
null,
uriBundle);
Run Code Online (Sandbox Code Playgroud)
这解决了com.android.providers.contacts.ContactsProvider2类似call方法将 uri 添加到-methodsmPreAuthorizedUris中使用的映射的情况query/update/...。
该调用的返回值被放入 Intent 中然后使用。