Android 系统应用蓝牙分享失败分析解决
文章目录
- [Android 系统应用蓝牙分享失败分析解决](#Android 系统应用蓝牙分享失败分析解决)
一、前言
Android 系统签名应用进行蓝牙分享会失败,近段开发蓝牙的时候发现了这个问题;
普通应用进行蓝牙文件分享是ok的,但是系统签名应用分享蓝牙文件就会失败。
这个问题目前在AML方案是有的,在安卓原生流程应该也是有这个问题的,但是在rk方案没遇到。
有可能是rk方案在某个流程做了处理。
这里简单分析一下处理的内容。
二、分析解决
1、主要日志
查看报错信息:
07-02 22:57:31.376 937 2839 W UriGrantsManagerService: For security reasons, the system cannot issue a Uri permission grant to content://com.mobisystems.office.RemoteFiles/YXNzZXRzOi8vc2FtcGxlcy9HZXR0aW5nX1N0YXJ0ZWQucGRm/0 [user 0]; use startActivityAsCaller() instead
07-02 22:57:31.379 937 2839 W Bundle : Key android.intent.extra.STREAM expected ArrayList<android.net.Uri> but value was of a different type. The default value <null> was returned.
07-02 22:57:31.380 937 2839 W Bundle : Attempt to cast generated internal exception:
07-02 22:57:31.380 937 2839 W Bundle : java.lang.ClassCastException: Cannot cast android.net.Uri$StringUri to java.util.ArrayList
07-02 22:57:31.380 937 2839 W UriGrantsManagerService: For security reasons, the system cannot issue a Uri permission grant to content://com.mobisystems.office.RemoteFiles/YXNzZXRzOi8vc2FtcGxlcy9HZXR0aW5nX1N0YXJ0ZWQucGRm/0 [user 0]; use startActivityAsCaller() instead
07-02 22:57:31.382 756 875 D DeviceHalAidl: [default] setAudioPortConfig
07-02 22:57:31.384 937 2839 V GrammaticalInflectionUtils: AttributionSource: AttributionSource { uid = 1002, packageName = null, attributionTag = null, token = android.os.Binder@8d82233, deviceId = 0, next = null } does not have READ_SYSTEM_GRAMMATICAL_GENDER permission.
07-02 22:57:31.385 937 2839 W OptProp : Cannot read opt property android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES
07-02 22:57:31.385 937 2839 W OptProp : Cannot read opt property android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE
上面的日志信息很重要。
日志看起来是权限报错:
... does not have READ_SYSTEM_GRAMMATICAL_GENDER permission.
但是实际并不是权限报错;尝试添加了权限也是不行的。
并且应用是系统签名,权限应该是比较大的。
2、具体分析日志
其实关键是下面这段日志:
UriGrantsManagerService: For security reasons, the system cannot issue a Uri permission grant to content://com.mobisystems.office.RemoteFiles/YXNzZXRzOi8vc2FtcGxlcy9HZXR0aW5nX1N0YXJ0ZWQucGRm/0 [user 0]; use startActivityAsCaller() instead
frameworks\base\services\core\java\com\android\server\uri\UriGrantsManagerService.java
/**
* Check if the targetPkg can be granted permission to access uri by
* the callingUid using the given modeFlags. Throws a security exception
* if callingUid is not allowed to do this. Returns the uid of the target
* if the URI permission grant should be performed; returns -1 if it is not
* needed (for example targetPkg already has permission to access the URI).
* If you already know the uid of the target, you can supply it in
* lastTargetUid else set that to -1.
*/
private int checkGrantUriPermissionUnlocked(int callingUid, String targetPkg, GrantUri grantUri,
int modeFlags, int lastTargetUid) {
if (!isContentUriWithAccessModeFlags(grantUri, modeFlags,
/* logAction */ "grant URI permission")) {
return -1;
}
if (targetPkg != null) {
if (DEBUG) Slog.v(TAG, "Checking grant " + targetPkg + " permission to " + grantUri);
}
// Bail early if system is trying to hand out permissions directly; it
// must always grant permissions on behalf of someone explicit.
final int callingAppId = UserHandle.getAppId(callingUid);
if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
if ("com.android.settings.files".equals(grantUri.uri.getAuthority())
|| "com.android.settings.module_licenses".equals(grantUri.uri.getAuthority())
|| "com.mobisystems.office.RemoteFiles".equals(grantUri.uri.getAuthority())
|| "com.skg.filemanager.provider".equals(grantUri.uri.getAuthority())
|| "com.debug.fastpass.fileprovider".equals(grantUri.uri.getAuthority())) {
// Exempted authority for
// 1. cropping user photos and sharing a generated license html
// file in Settings app
// 2. sharing a generated license html file in TvSettings app
// 3. Sharing module license files from Settings app
} else {
//这里就是报错的地方:::
Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
+ " grant to " + grantUri + "; use startActivityAsCaller() instead");
return -1;
}
}
...
首先上面注释的地方就写了:if callingUid is not allowed to do this. 不允许系统签名应用使用临时uri地址。
代码中有判断 callingAppId == SYSTEM_UID 如果没有添加白名单就会报错,打印:For security reasons ...
这个是处于系统安全原因考虑,不允许系统签名使用临时的uri访问系统。
蓝牙分享和某些投屏情况是需要临时uri进行控制系统的,但是系统签名应用权限比较大,所以被禁止了。
如果需要不被禁止可以在上面添加白名单,比如:
com.debug.fastpass.fileprovider 或者 com.mobisystems.office.RemoteFiles
fileprovider 的名称可以在应用的AndroidManifest中查看,也可以在报错信息中查看
比如上面报错就有:
cannot issue a Uri permission grant to content://com.mobisystems.office.RemoteFiles/...
只要提取content://XXX/ 中的XXX内容就可以了。
上面的代码如果整个去掉 (callingAppId == SYSTEM_UID) || 也是可以的,就会去除校验所有系统签名应用;
但是有可能造成EDLA认证失败。
另外在rk方案的代码查看,是没有修改到 UriGrantsManagerService.java 的,
不清楚是在这个流程前面还是后面进行了处理。。。
三、其他
1、小结
系统应用无法进行蓝牙文件分享是因为framework中做了安全校验;
限制了系统签名应用进行临时uri的访问。
如果要去除这个现实可以在 UriGrantsManagerService.java 进行适配修改。
2、普通应用蓝牙文件分享知识
Android蓝牙文件分享代码实战指南:
通过蓝牙技术,用户可以在设备之间快速传输图片、音频、文档等各类文件。
本文基于实际项目经验,详细讲解 Android 蓝牙文件分享的完整实现方案,
包括单文件分享、多文件批量分享、权限配置、关键 API 使用及常见问题解决方案。
https://blog.csdn.net/wenzhi20102321/article/details/162794687