具体错误如下:
java.lang.SecurityException: Permission Denial: getTaskThumbnails() from pid=2881, uid=10077 requires android.permission.READ_FRAME_BUFFER
意思就是应用没有android.permission.READ_FRAME_BUFFER,但是我已经在AndroidManifest.xml中赋予了该权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
还是不行,就只能跟踪源码了,首先我们可以差点在调用getTaskThumbnails的时候,在ActivityManagerService中的getTaskThumbnails会进行权限检测,调用enforceCallingPermission,enforceCallingPermission又调用checkComponentPermission,最终会调用PackageManagerService的checkUidPermission
public int checkUidPermission(String permName, int uid) {
synchronized (mPackages) {
Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
if (obj != null) {
GrantedPermissions gp = (GrantedPermissions)obj;
if (gp.grantedPermissions.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
} else {
HashSet<String> perms = mSystemPermissions.get(uid);
if (perms != null && perms.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
}
}
return PackageManager.PERMISSION_DENIED;
}
这里会获取该apk赋予的权限,看里面是否有需要请求的权限。
我们跟踪代码的时候,发现这里面没有请求的权限android.permission.READ_FRAME_BUFFER,这是为什么呢,原因可能是安装的时候,解析AndroidManifest.xml的时候没有给他赋予这个权限,添加权限在grantPermissionsLPw函数里面,如下代码获取应用需要的权限对应的等级:
final BasePermission bp = mSettings.mPermissions.get(name);
if (DEBUG_INSTALL) {
if (gp != ps) {
Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
}
}
if (bp == null || bp.packageSetting == null) {
Slog.w(TAG, "Unknown permission " + name
+ " in package " + pkg.packageName);
continue;
}
final String perm = bp.name;
boolean allowed;
boolean allowedSig = false;
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
Android里面共有6个权限等级,定义在PermissionInfo文件。
/**
* Dangerous value for {@link #protectionLevel}, corresponding
* to the <code>dangerous</code> value of
* {@link android.R.attr#protectionLevel}.
*/
public static final int PROTECTION_DANGEROUS = 1;
/**
* System-level value for {@link #protectionLevel}, corresponding
* to the <code>signature</code> value of
* {@link android.R.attr#protectionLevel}.
*/
public static final int PROTECTION_SIGNATURE = 2;
/**
* System-level value for {@link #protectionLevel}, corresponding
* to the <code>signatureOrSystem</code> value of
* {@link android.R.attr#protectionLevel}.
*/
public static final int PROTECTION_SIGNATURE_OR_SYSTEM = 3;
/**
* Additional flag for {@link #protectionLevel}, corresponding
* to the <code>system</code> value of
* {@link android.R.attr#protectionLevel}.
*/
public static final int PROTECTION_FLAG_SYSTEM = 0x10;
/**
* Additional flag for {@link #protectionLevel}, corresponding
* to the <code>development</code> value of
* {@link android.R.attr#protectionLevel}.
*/
public static final int PROTECTION_FLAG_DEVELOPMENT = 0x20;
android的权限大部分定义在framework-res.apk里面,部分如下所示:
<permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
android:label="@string/permlab_changeComponentState"
android:description="@string/permdesc_changeComponentState"
android:protectionLevel="signature|system" />
<!-- @hide Allows an application to grant or revoke specific permissions. -->
<permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS"
android:label="@string/permlab_grantRevokePermissions"
android:description="@string/permdesc_grantRevokePermissions"
android:protectionLevel="signature" />
<!-- Allows an application to use SurfaceFlinger's low level features.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
android:label="@string/permlab_accessSurfaceFlinger"
android:description="@string/permdesc_accessSurfaceFlinger"
android:protectionLevel="signature" />
<!-- Allows an application to take screen shots and more generally
get access to the frame buffer data.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.READ_FRAME_BUFFER"
android:label="@string/permlab_readFrameBuffer"
android:description="@string/permdesc_readFrameBuffer"
android:protectionLevel="signature|system" />
这些权限最后在android系统起来后会保存到一个/data/system/packages.xml,如:
<item name="android.permission.BROADCAST_STICKY" package="android" />
<item name="android.permission.GRANT_REVOKE_PERMISSIONS" package="android" protection="2" />
<item name="android.permission.WRITE_USER_DICTIONARY" package="android" />
<item name="android.permission.READ_FRAME_BUFFER" package="android" protection="18" />
言归正传,我们看安装时候对权限的解析,通过如下
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
获取对应的权限等级,然后判断各个级别是否允许授权:
if (level == PermissionInfo.PROTECTION_NORMAL
|| level == PermissionInfo.PROTECTION_DANGEROUS) {
// We grant a normal or dangerous permission if any of the following
// are true:
// 1) The permission is required
// 2) The permission is optional, but was granted in the past
// 3) The permission is optional, but was requested by an
// app in /system (not /data)
//
// Otherwise, reject the permission.
allowed = (required || origPermissions.contains(perm)
|| (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
} else if (bp.packageSetting == null) {
// This permission is invalid; skip it.
allowed = false;
} else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
if (allowed) {
allowedSig = true;
}
} else {
allowed = false;
}
如果允许,则添加到该apk拥有的权限列表里面:
if (allowed) {
if (!gp.grantedPermissions.contains(perm)) {
changedPermission = true;
gp.grantedPermissions.add(perm);
gp.gids = appendInts(gp.gids, bp.gids);
} else if (!ps.haveGids) {
gp.gids = appendInts(gp.gids, bp.gids);
}
}
跟踪代码我们可以发现,虽然apk请求了android.permission.READ_FRAME_BUFFER权限,但并没有赋予他,原因是签名不一致(签名需要跟定义权限的apk一致),这里获取到的level=PROTECTION_SIGNATURE,调用grantSignaturePermission判断是否获取权限。
修改对策:
1、修改apk签名
2、修改android.permission.READ_FRAME_BUFFER等级