1. 测验基本信息描绘
测验模块:
CtsHardwareTestCases
测验case:
android.hardware.fingerprint.cts.FingerprintManagerTest#test_hasFingerprintHardware
该问题CTS 测验pass,刷GSI 后测验fail。
报错信息为:
03-06 11:17:09 I/ModuleListener: [1/1] e87aea03 android.hardware.cts android.hardware.fingerprint.cts.FingerprintManagerTest#test_hasFingerprintHardware FAILURE: junit.framework.AssertionFailedError
at junit.framework.Assert.fail(Assert.java:48)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertTrue(Assert.java:27)
at android.hardware.fingerprint.cts.FingerprintManagerTest.test_hasFingerprintHardware(FingerprintManagerTest.java:86)
2. 问题剖析
2.1 错误信息剖析
- 依据测验用例可知是指纹解锁相关的case
- 依据测验报告的fail信息可知,在FingerprintManagerTest.java文件的第86履行test_hasFingerprintHardware办法时断语fail,导致测验fail
2.2 源码剖析
# FingerprintManagerTest.java
// 指纹服务管理类
private FingerprintManager mFingerprintManager;
// 是否支撑指纹解说
boolean mHasFingerprintManager;
@Override
public void setUp() throws Exception {
super.setUp();
mAuthState = AuthState.AUTH_UNKNOWN;
PackageManager pm = getContext().getPackageManager();
// FEATURE_FINGERPRINT = "android.hardware.fingerprint"
if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
mHasFingerprintManager = true;
// 假如支撑指纹解说,则拿到对应的服务
mFingerprintManager = (FingerprintManager)
getContext().getSystemService(Context.FINGERPRINT_SERVICE);
}
}
@Presubmit
public void test_hasFingerprintHardware() {
if (!mHasFingerprintManager) {
return; // skip test if no fingerprint feature
}
// 报错行
assertTrue(mFingerprintManager.isHardwareDetected());
}
-
- 报错行在 assertTrue 这句断语,需求 isHardwareDetected() 回来true ,可是实际上回来了false,导致fail
-
- 能履行到这一句的前提是 mHasFingerprintManager 为true,假如其值为false表明当时设备不支撑指纹解说功能,当时case就会越过
-
- 可是当时报错的是GSI,并且在CTS测验中该case没有越过,阐明当时设备是需求支撑指纹解锁的, 从设置硬件规划也能够确定。 另外能够通过以下指令来获取feature的支撑
adb shell "pm list features | grep -c "android.hardware.fingerprint""
也便是说当时case fail的原因是支撑了指纹解锁的feature,可是isHardwareDetected()回来了false。
那么当时需求剖析的点便是:为什么isHardwareDetected()回来了false ?
2.2.1 回来false的逻辑盯梢
# FingerprintManager.java
// 指纹服务 (FingerprintService)
private IFingerprintService mService;
/**
* Determine if fingerprint hardware is present and functional.
* 确定指纹硬件是否存在并正常作业。
* @return true if hardware is present and functional, false otherwise.
* 假如硬件存在并正常作业,则回来true,否则回来false
* @deprecated See {@link BiometricPrompt} and
* {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE}
*/
@Deprecated
@RequiresPermission(USE_FINGERPRINT)
public boolean isHardwareDetected() {
......
if (mService != null) {
try {
return mService.isHardwareDetectedDeprecated(
mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else {
Slog.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
}
return false;
}
-
- 依据注释,和fail的原因,知道当时回来 false, 也就阐明硬件不存在,或者没有正常作业。硬件肯定是存在的,那fail的原因便是没有正常作业
-
- 回来有2种可能,一种是 mService为null, 一种是 isHardwareDetectedDeprecated办法回来false
假如是 mService 为null 回来false的话, 会有”isFingerprintHardwareDetected(): Service not connected!” 的log打印,可是实际上并没有这段log的打印。
- 回来有2种可能,一种是 mService为null, 一种是 isHardwareDetectedDeprecated办法回来false
所以是FingerprintService::isHardwareDetectedDeprecated办法回来了false导致测验的fail
# FingerprintService.java
@Override // Binder call
public boolean isHardwareDetectedDeprecated(String opPackageName, String attributionTag) {
if (!canUseFingerprint(
opPackageName,
attributionTag,
false /* foregroundOnly */,
Binder.getCallingUid(),
Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
return false;
}
final long token = Binder.clearCallingIdentity();
try {
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetectedDeprecated, caller: "
+ opPackageName);
// 这儿回来的false
return false;
}
return provider.second.isHardwareDetected(provider.first);
} finally {
Binder.restoreCallingIdentity(token);
}
}
这儿有2个return的当地, 可是第二个回来false的当地有log打印。
在测验log中能够看到如下日志, 阐明回来false的当地是 provider 这个变量为null
03:39:05.206 1000 2206 6756 E FingerprintService: No providers found
03:39:05.207 1000 2206 6756 W FingerprintService: Null provider for isHardwareDetectedDeprecated, caller: android.hardware.cts
# FingerprintService.java
@Nullable
private Pair<Integer, ServiceProvider> getSingleProvider() {
final List<FingerprintSensorPropertiesInternal> properties = getSensorProperties();
if (properties.isEmpty()) {
// 打印log, 回来null
Slog.e(TAG, "No providers found");
return null;
}
......
}
能够看到这儿打印的log,和回来null。
下一步看getSensorProperties 办法为什么回来null
# FingerprintService.java
// 列表
@NonNull private final List<FingerprintSensorPropertiesInternal> mSensorProps;
@NonNull
private List<FingerprintSensorPropertiesInternal> getSensorProperties() {
synchronized (mLock) {
return mSensorProps;
}
}
现在的问题变为: 为什么 mSensorProps 在刷了GSI 后会为null,搜到mSensorProps数据的增加在 FingerprintService::registerAuthenticators中。
# FingerprintService.java
@NonNull private final List<FingerprintSensorPropertiesInternal> mSensorProps;
@Override // Binder call
public void registerAuthenticators(
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
......
handler.post(() -> {
addHidlProviders(hidlSensors);
addAidlProviders();
......
synchronized (mLock) {
for (ServiceProvider provider : mServiceProviders) {
// 遍历mServiceProviders往mSensorProps增加数据
mSensorProps.addAll(provider.getSensorProperties());
}
}
......
broadcastAllAuthenticatorsRegistered(); // 这儿会打印 FingerprintService: mSensorProps is empty, 也能阐清晰实是 mSensorProps没数据
});
}
private void addHidlProviders(List<FingerprintSensorPropertiesInternal> hidlSensors) {
for (FingerprintSensorPropertiesInternal hidlSensor : hidlSensors) {
final Fingerprint21 fingerprint21;
if ((Build.IS_USERDEBUG || Build.IS_ENG)
&& getContext().getResources().getBoolean(R.bool.allow_test_udfps)
&& Settings.Secure.getIntForUser(getContext().getContentResolver(),
Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
UserHandle.USER_CURRENT) != 0) {
fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
mBiometricStateCallback, hidlSensor,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
BiometricContext.getInstance(getContext()));
} else {
fingerprint21 = Fingerprint21.newInstance(getContext(),
mBiometricStateCallback, hidlSensor, mHandler,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
// 对mServiceProviders增加数据
mServiceProviders.add(fingerprint21);
}
}
-
- 剖析的 mSensorProps 数据增加是开机就履行了的流程,不是测验中
-
- mSensorProps 的数据增加依赖 mServiceProviders变量
-
- mServiceProviders 的数据增加在 FingerprintService::addHidlProviders
-
- FingerprintService::addHidlProviders 又是在 FingerprintService:: registerAuthenticators 中
所以现在需求重视 FingerprintService:: registerAuthenticators 办法调用传递过来的参数为什么为null?
这个办法是public的,调用在AuthService中
2.2.2 开机过程指纹模块的处理
# AuthService.java
private void registerAuthenticators(@Nullable SensorConfig[] hidlSensors) {
List<FingerprintSensorPropertiesInternal> hidlFingerprintSensors = new ArrayList<>();
List<FaceSensorPropertiesInternal> hidlFaceSensors = new ArrayList<>();
// Iris doesn't have IrisSensorPropertiesInternal, using SensorPropertiesInternal instead.
List<SensorPropertiesInternal> hidlIrisSensors = new ArrayList<>();
if (hidlSensors != null) {
for (SensorConfig sensor : hidlSensors) {
// 打印log
Slog.d(TAG, "Registering HIDL ID: " + sensor.id + " Modality: " + sensor.modality
+ " Strength: " + sensor.strength);
switch (sensor.modality) {
case TYPE_FINGERPRINT:
// 处理数据
hidlFingerprintSensors.add(
getHidlFingerprintSensorProps(sensor.id, sensor.strength));
break;
......
}
}
}
final IFingerprintService fingerprintService = mInjector.getFingerprintService();
if (fingerprintService != null) {
try {
// 履行到上面的registerAuthenticators办法,传递hidlFingerprintSensors
fingerprintService.registerAuthenticators(hidlFingerprintSensors);
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException when registering fingerprint authenticators", e);
}
} ......
}
假如参数 hidlSensors不为空,就会履行这儿的逻辑,并且会打印log。 不刷GSI的设备抓取开机log是能看到这儿的 “Registering HIDL ID: XX” 的日志, 刷了GSI的却没有。
阐明参数传过来的hidlSensors就为null了。
registerAuthenticators办法的调用在 AuthService::onStart中。
# AuthService.java
@Override
public void onStart() {
mBiometricService = mInjector.getBiometricService();
// 重点对象,存储着指纹相关的装备
final SensorConfig[] hidlConfigs;
// 承认过,这儿回来true
if (!mInjector.isHidlDisabled(getContext())) {
final int firstApiLevel = SystemProperties.getInt(SYSPROP_FIRST_API_LEVEL, 0);
final int apiLevel = SystemProperties.getInt(SYSPROP_API_LEVEL, firstApiLevel);
// 关键,读取装备
String[] configStrings = mInjector.getConfiguration(getContext());
if (configStrings.length == 0 && apiLevel == Build.VERSION_CODES.R) {
......
Slog.w(TAG, "Found R vendor partition without config_biometric_sensors");
// 不走这, 没有上面的log,并且当时设备是T的 ,不是R
configStrings = generateRSdkCompatibleConfiguration();
}
// 走这
hidlConfigs = new SensorConfig[configStrings.length];
for (int i = 0; i < configStrings.length; ++i) {
hidlConfigs[i] = new SensorConfig(configStrings[i]);
}
} else {
// 不走这, 扫除
hidlConfigs = null;
}
// Registers HIDL and AIDL authenticators, but only HIDL configs need to be provided.
// 关键函数
registerAuthenticators(hidlConfigs);
mInjector.publishBinderService(this, mImpl);
}
这儿的关键在于末尾调用 registerAuthenticators办法传递是参数 hidlConfigs。
依据注释里的信息, 最终走的是下面这块。
hidlConfigs = new SensorConfig[configStrings.length];
也便是说hidlConfigs的数据最终被configStrings影响。
这个 configStrings 的值是 Injector::getConfiguration 回来的。 这个Injector便是 AuthService 的内部类
# AuthService.java
public static class Injector {
...
@VisibleForTesting
public String[] getConfiguration(Context context) {
return context.getResources().getStringArray(R.array.config_biometric_sensors);
}
...
}
能够看到读取了装备config_biometric_sensors的值
通过承认,当时项目这个值在android/frameworks/base/core/res/res/values/config.xml下
<!-- List of biometric sensors on the device, in decreasing strength. Consumed by AuthService
when registering authenticators with BiometricService. Format must be ID:Modality:Strength,
where: IDs are unique per device, Modality as defined in BiometricAuthenticator.java,
and Strength as defined in Authenticators.java -->
<string-array name="config_biometric_sensors" translatable="false" >
<item>0:2:15</item>
</string-array>
依据注释,这儿是指纹传感器的强度,这3个值也是定义在代码里的。
也便是说当时问题是因为刷了system.img后没有这个值导致的fail。
在普通版别和GSI 版别别离履行下面指令获取这个装备也能承认
adb shell cmd overlay lookup android android:array/config_biometric_sensors
2.3 正常和GSI版别开机log比照,以及调用链整理
正常开机log:
Line 12436: 02-06 01:40:17.849 2214 2214 D SystemServerTiming: StartAuthService
Line 12437: 02-06 01:40:17.849 2214 2214 I SystemServiceManager: Starting com.android.server.biometrics.AuthService
Line 12444: 02-06 01:40:17.851 2214 2214 D AuthService: Registering HIDL ID: 0 Modality: 2 Strength: 15
fail版别GSI的开机log:
01-09 13:59:46.272 2104 2104 D SystemServerTiming: StartAuthService
Line 13495: 01-09 13:59:46.276 2104 2520 E FingerprintService: mSensorProps is empty
调用链如下:
FingerprintManagerTest::test_hasFingerprintHardware
mHasFingerprintManager -- 是否支撑指纹解锁feature, 不支撑则 skip
FingerprintManager::isHardwareDetected -- 回来false导致测验fail
FingerprintService::isHardwareDetectedDeprecated
FingerprintService::getSingleProvider
FingerprintService::getSensorProperties
mSensorProps 数据的增加,这些流程在开机的时分履行
AuthService::onStart
AuthService::registerAuthenticators
FingerprintService::registerAuthenticators
FingerprintService::addHidlProviders
3. 解决方案
知道是 config_biometric_sensors 这个装备导致的,那便是要在vender下装备这个值,使刷完GSI后还能有这个值就好了。