support-v4 包中FingerprintManagerC
之前在中兴的时候,在L版本时期自研指纹框架,当时也只提供给了公司内部模块使用,并没有什么问题。
在升级到M之后,作为系统标准接口,三方应用使用该接口的也多了起来。与公司的合作项目中,在使用指纹接口发现指纹无法使用。
首先我们确定指纹器件是没有问题的,指纹解锁,支付等功能都正常。自己单独写了demo检查也没发现问题。与合作公司沟通,了解到他们使用的是support-v4 包中FingerprintManagerCompat。同时在小米的M版本机型中同样存在该问题。
于是开始排查,问题很直接,很明显:
private static FingerprintManager getFingerprintManagerOrNull(@NonNull Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
return context.getSystemService(FingerprintManager.class);
} else {
return null;
}
}
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)返回false。
进入PackageManagerService(SDK中源码位置Sdk/sources/android-27/com/android/server/pm,编译环境中/frameworks/base/services/core/java/com/android/server/pm/
,可通过AndroidXRef查看),查看
public boolean hasSystemFeature(String name, int version) {
// allow instant applications
synchronized (mAvailableFeatures) {
final FeatureInfo feat = mAvailableFeatures.get(name);
if (feat == null) {
return false;
} else {
return feat.version >= version;
}
}
}
得知系统会在PMS的构造函数中进行AvailableFeatures的缓存,
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
...
}
进一步查看SystemConfig源码(SDK中源码位置Sdk/sources/android-27/com/android/server/,编译环境中/frameworks/base/core/java/com/android/server/
)中在SystemConfig构造函数中会在 /system/etc/sysconfig , /system/etc/permissions ,/vendor/etc/sysconfig , /vendor/etc/permissions ,/oem/etc/sysconfig , /oem/etc/permissions ,/odm/etc/sysconfig , /odm/etc/permissions 几个目录中去加载feature,要求为xml文件。内容为
<permissions>
<feature name="android.hardware.fingerprint" />
</permissions>
在编译环境中搜索 /frameworks/native/data/etc/
下存在android.hardware.fingerprint.xml
在检查公司自定义的脚本中,漏掉了对该文件的拷贝,修改mk文件,将改文件拷贝至system/etc/permissions/下后恢复正常。
如果不用V4包中的FingerprintManagerCompat,而是用M后SDK中FingerprintManagerz中isHardwareDetected()和hasEnrolledFingerprints()来判断并不会出问题,而我们内部总是这样用的。但是对于第三方开发者来说,这种差异化却是不必要的麻烦。在后续工作应该多注意规避这些低级错误。