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 错误信息剖析

  1. 依据测验用例可知是指纹解锁相关的case
  2. 依据测验报告的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());
    }
    1. 报错行在 assertTrue 这句断语,需求 isHardwareDetected() 回来true ,可是实际上回来了false,导致fail
    1. 能履行到这一句的前提是 mHasFingerprintManager 为true,假如其值为false表明当时设备不支撑指纹解说功能,当时case就会越过
    1. 可是当时报错的是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;
    }
    1. 依据注释,和fail的原因,知道当时回来 false, 也就阐明硬件不存在,或者没有正常作业。硬件肯定是存在的,那fail的原因便是没有正常作业
    1. 回来有2种可能,一种是 mService为null, 一种是 isHardwareDetectedDeprecated办法回来false
      假如是 mService 为null 回来false的话, 会有”isFingerprintHardwareDetected(): Service not connected!” 的log打印,可是实际上并没有这段log的打印。

所以是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);
            }
        }
    1. 剖析的 mSensorProps 数据增加是开机就履行了的流程,不是测验中
    1. mSensorProps 的数据增加依赖 mServiceProviders变量
    1. mServiceProviders 的数据增加在 FingerprintService::addHidlProviders
    1. 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后还能有这个值就好了。