Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc954808 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6473661 from 91c5deaf to rvc-release

Change-Id: I1eeb8a9002d638d9814c9935c2af478b69ae7fc8
parents 8c087f86 91c5deaf
Loading
Loading
Loading
Loading
+46 −26
Original line number Diff line number Diff line
@@ -2813,7 +2813,7 @@ enum VehicleProperty : int32_t {
     *
     * To query the association, the Android system gets the property, passing a VehiclePropValue
     * containing the types of associations are being queried, as defined by
     * UserIdentificationGetRequest. The HAL must return right away, updating the VehiclePropValue
     * UserIdentificationGetRequest. The HAL must return right away, returning a VehiclePropValue
     * with a UserIdentificationResponse. Notice that user identification should have already
     * happened while system is booting up and the VHAL implementation should only return the
     * already identified association (like the key FOB used to unlock the car), instead of starting
@@ -2828,45 +2828,50 @@ enum VehicleProperty : int32_t {
     * For example, to query if the current user (10) is associated with the FOB that unlocked the
     * car and a custom mechanism provided by the OEM, the request would be:
     *
     * int32[0]: 10  (Android user id)
     * int32[1]: 0   (Android user flags)
     * int32[2]: 2   (number of types queried)
     * int32[3]: 1   (1st type queried, UserIdentificationAssociationType::KEY_FOB)
     * int32[4]: 101 (2nd type queried, UserIdentificationAssociationType::CUSTOM_1)
     * int32[0]: 42  // request id
     * int32[1]: 10  (Android user id)
     * int32[2]: 0   (Android user flags)
     * int32[3]: 2   (number of types queried)
     * int32[4]: 1   (1st type queried, UserIdentificationAssociationType::KEY_FOB)
     * int32[5]: 101 (2nd type queried, UserIdentificationAssociationType::CUSTOM_1)
     *
     * If the user is associated with the FOB but not with the custom mechanism, the response would
     * be:
     *
     * int32[9]: 2   (number of associations in the response)
     * int32[1]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
     * int32[2]: 2   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
     * int32[3]: 101 (2st type: UserIdentificationAssociationType::CUSTOM_1)
     * int32[4]: 4   (2nd value: UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER)
     * int32[0]: 42  // request id
     * int32[1]: 2   (number of associations in the response)
     * int32[2]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
     * int32[3]: 2   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
     * int32[4]: 101 (2st type: UserIdentificationAssociationType::CUSTOM_1)
     * int32[5]: 4   (2nd value: UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER)
     *
     * Then to associate the user with the custom mechanism, a set request would be made:
     *
     * int32[0]: 10  (Android user id)
     * int32[0]: 0   (Android user flags)
     * int32[1]: 1   (number of associations being set)
     * int32[2]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
     * int32[3]: 1   (1st value: UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER)
     * int32[0]: 42  // request id
     * int32[1]: 10  (Android user id)
     * int32[2]: 0   (Android user flags)
     * int32[3]: 1   (number of associations being set)
     * int32[4]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
     * int32[5]: 1   (1st value: UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER)
     *
     * If the request succeeded, the response would be simply:
     *
     * int32[0]: 2   (number of associations in the response)
     * int32[1]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
     * int32[2]: 1   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
     * int32[0]: 42  // request id
     * int32[1]: 1   (number of associations in the response)
     * int32[2]: 101 (1st type: UserIdentificationAssociationType::CUSTOM_1)
     * int32[3]: 1   (1st value: UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER)
     *
     * Notice that the set request adds associations, but doesn't remove the existing ones. In the
     * example above, the end state would be 2 associations (FOB and CUSTOM_1). If we wanted to
     * associate the user with just CUSTOM_1 but not FOB, then the request should have been:
     *
     * int32[0]: 10  (Android user id)
     * int32[1]: 2   (number of types set)
     * int32[2]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
     * int32[3]: 2   (1st value: UserIdentificationAssociationValue::DISASSOCIATE_CURRENT_USER)
     * int32[3]: 101 (2nd type: UserIdentificationAssociationType::CUSTOM_1)
     * int32[5]: 1   (2nd value: UserIdentificationAssociationValue::ASSOCIATE_CURRENT_USER)
     * int32[0]: 42  // request id
     * int32[1]: 10  (Android user id)
     * int32[2]: 2   (number of types set)
     * int32[3]: 1   (1st type: UserIdentificationAssociationType::KEY_FOB)
     * int32[4]: 2   (1st value: UserIdentificationAssociationValue::DISASSOCIATE_CURRENT_USER)
     * int32[5]: 101 (2nd type: UserIdentificationAssociationType::CUSTOM_1)
     * int32[6]: 1   (2nd value: UserIdentificationAssociationValue::ASSOCIATE_CURRENT_USER)
     *
     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
     * @access VehiclePropertyAccess:READ_WRITE
@@ -4638,6 +4643,11 @@ enum UserIdentificationAssociationSetValue : int32_t {
 * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
 */
struct UserIdentificationGetRequest {
    /**
     * Id of the request being responded.
     */
    UserRequestId requestId;

    /**
     * Information about the current foreground Android user.
     */
@@ -4661,6 +4671,11 @@ struct UserIdentificationGetRequest {
 * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
 */
struct UserIdentificationSetRequest {
    /**
     * Id of the request being responded.
     */
    UserRequestId requestId;

    /**
     * Information about the current foreground Android user.
     */
@@ -4674,7 +4689,7 @@ struct UserIdentificationSetRequest {
    /**
     * Associations being set.
     */
    vec<UserIdentificationAssociationSetValue> associations;
    vec<UserIdentificationSetAssociation> associations;
};

/**
@@ -4684,6 +4699,11 @@ struct UserIdentificationSetRequest {
 * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
 */
struct UserIdentificationResponse {
    /**
     * Id of the request being responded.
     */
    UserRequestId requestId;

    /**
     * Number of associations being returned.
     */
+13 −9
Original line number Diff line number Diff line
@@ -204,7 +204,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
    void Test_setActiveConfigWithConstraints(
            const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss);

    void sendRefreshFrame(const VsyncPeriodChangeTimeline&);
    void sendRefreshFrame(const VsyncPeriodChangeTimeline*);

    void waitForVsyncPeriodChange(Display display, const VsyncPeriodChangeTimeline& timeline,
                                  int64_t desiredTimeNanos, int64_t oldPeriodNanos,
@@ -294,7 +294,7 @@ TEST_P(GraphicsComposerHidlCommandTest, getDisplayVsyncPeriod) {
                                           display, config, constraints, &timeline));

            if (timeline.refreshRequired) {
                sendRefreshFrame(timeline);
                sendRefreshFrame(&timeline);
            }
            waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, 0,
                                     expectedVsyncPeriodNanos);
@@ -350,7 +350,7 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_BadConfig) {
    }
}

TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_SeamlessNotAllowed) {
TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_SeamlessNotAllowed) {
    VsyncPeriodChangeTimeline timeline;
    IComposerClient::VsyncPeriodChangeConstraints constraints;

@@ -365,6 +365,7 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_SeamlessNotAllow
                    display, config2, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP);
            if (configGroup1 != configGroup2) {
                mComposerClient->setActiveConfig(display, config1);
                sendRefreshFrame(nullptr);
                EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED,
                          mComposerClient->setActiveConfigWithConstraints(display, config2,
                                                                          constraints, &timeline));
@@ -377,11 +378,13 @@ static inline auto toTimePoint(nsecs_t time) {
    return std::chrono::time_point<std::chrono::steady_clock>(std::chrono::nanoseconds(time));
}

void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTimeline& timeline) {
void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTimeline* timeline) {
    if (timeline != nullptr) {
        // Refresh time should be before newVsyncAppliedTimeNanos
    EXPECT_LT(timeline.refreshTimeNanos, timeline.newVsyncAppliedTimeNanos);
        EXPECT_LT(timeline->refreshTimeNanos, timeline->newVsyncAppliedTimeNanos);

    std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos));
        std::this_thread::sleep_until(toTimePoint(timeline->refreshTimeNanos));
    }

    mWriter->selectDisplay(mPrimaryDisplay);
    mComposerClient->setPowerMode(mPrimaryDisplay, V2_1::IComposerClient::PowerMode::ON);
@@ -453,6 +456,7 @@ void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints(
    for (Display display : mComposerCallback->getDisplays()) {
        forEachTwoConfigs(display, [&](Config config1, Config config2) {
            mComposerClient->setActiveConfig(display, config1);
            sendRefreshFrame(nullptr);

            int32_t vsyncPeriod1 = mComposerClient->getDisplayAttribute_2_4(
                    display, config1, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD);
@@ -478,7 +482,7 @@ void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints(
                    // callback
                    std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) + 100ms);
                }
                sendRefreshFrame(timeline);
                sendRefreshFrame(&timeline);
            }
            waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, vsyncPeriod1,
                                     vsyncPeriod2);
@@ -493,7 +497,7 @@ void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints(

            if (newTimelime.has_value()) {
                if (timeline.refreshRequired) {
                    sendRefreshFrame(newTimelime.value());
                    sendRefreshFrame(&newTimelime.value());
                }
                waitForVsyncPeriodChange(display, newTimelime.value(), constraints.desiredTimeNanos,
                                         vsyncPeriod1, vsyncPeriod2);
+4 −0
Original line number Diff line number Diff line
@@ -296,6 +296,10 @@ MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert) {
    const uint8_t* p = cert.data();
    X509_Ptr x509(d2i_X509(nullptr, &p, cert.size()));
    if (!x509.get()) {
        LOG(ERROR) << "Error converting DER";
        return {ErrorCode::INVALID_ARGUMENT, {}};
    }

    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
    if (!oid.get()) {
+71 −30
Original line number Diff line number Diff line
@@ -14,6 +14,9 @@
 * limitations under the License.
 */

#define LOG_TAG "keymaster_hidl_hal_test"
#include <cutils/log.h>

#include "Keymaster4_1HidlTest.h"

#include <cutils/properties.h>
@@ -23,6 +26,10 @@
#include <keymasterV4_1/attestation_record.h>
#include <keymasterV4_1/authorization_set.h>

// Not to dump the attestation by default. Can enable by specify the parameter
// "--dump_attestations" on lunching VTS
static bool dumpAttestations = false;

namespace android::hardware::keymaster::V4_0 {

bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
@@ -57,6 +64,10 @@ string bin2hex(const hidl_vec<uint8_t>& data) {
    return retval;
}

inline void dumpContent(string content) {
    std::cout << content << std::endl;
}

struct AuthorizationSetDifferences {
    string aName;
    string bName;
@@ -126,6 +137,23 @@ void check_root_of_trust(const RootOfTrust& root_of_trust) {
    }
}

bool tag_in_list(const KeyParameter& entry) {
    // Attestations don't contain everything in key authorization lists, so we need to filter
    // the key lists to produce the lists that we expect to match the attestations.
    auto tag_list = {
            Tag::INCLUDE_UNIQUE_ID, Tag::BLOB_USAGE_REQUIREMENTS, Tag::EC_CURVE,
            Tag::HARDWARE_TYPE,     Tag::VENDOR_PATCHLEVEL,       Tag::BOOT_PATCHLEVEL,
            Tag::CREATION_DATETIME,
    };
    return std::find(tag_list.begin(), tag_list.end(), (V4_1::Tag)entry.tag) != tag_list.end();
}

AuthorizationSet filter_tags(const AuthorizationSet& set) {
    AuthorizationSet filtered;
    std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list);
    return filtered;
}

void check_attestation_record(AttestationRecord attestation, const HidlBuf& challenge,
                              AuthorizationSet expected_sw_enforced,
                              AuthorizationSet expected_hw_enforced,
@@ -144,9 +172,9 @@ void check_attestation_record(AttestationRecord attestation, const HidlBuf& chal
    attestation.software_enforced.Sort();
    attestation.hardware_enforced.Sort();

    EXPECT_EQ(expected_sw_enforced, attestation.software_enforced)
    EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(attestation.software_enforced))
            << DIFFERENCE(expected_sw_enforced, attestation.software_enforced);
    EXPECT_EQ(expected_hw_enforced, attestation.hardware_enforced)
    EXPECT_EQ(filter_tags(expected_hw_enforced), filter_tags(attestation.hardware_enforced))
            << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced);
}

@@ -155,8 +183,8 @@ void check_attestation_record(AttestationRecord attestation, const HidlBuf& chal
using std::string;
using DeviceUniqueAttestationTest = Keymaster4_1HidlTest;

TEST_P(DeviceUniqueAttestationTest, StrongBoxOnly) {
    if (SecLevel() != SecurityLevel::STRONGBOX) return;
TEST_P(DeviceUniqueAttestationTest, NonStrongBoxOnly) {
    if (SecLevel() == SecurityLevel::STRONGBOX) return;

    ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
                                                         .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -197,7 +225,7 @@ TEST_P(DeviceUniqueAttestationTest, Rsa) {
                                  .RsaSigningKey(2048, 65537)
                                  .Digest(Digest::SHA_2_256)
                                  .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
                                          .Authorization(TAG_CREATION_DATETIME, 1))));
                                  .Authorization(TAG_INCLUDE_UNIQUE_ID))));

    hidl_vec<hidl_vec<uint8_t>> cert_chain;
    HidlBuf challenge("challenge");
@@ -209,14 +237,14 @@ TEST_P(DeviceUniqueAttestationTest, Rsa) {
                                        .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
                                &cert_chain)));

    EXPECT_EQ(1U, cert_chain.size());
    EXPECT_EQ(2U, cert_chain.size());
    if (dumpAttestations) dumpContent(bin2hex(cert_chain[0]));
    auto [err, attestation] = parse_attestation_record(cert_chain[0]);
    EXPECT_EQ(ErrorCode::OK, err);
    ASSERT_EQ(ErrorCode::OK, err);

    check_attestation_record(attestation, challenge,
                             /* sw_enforced */
                             AuthorizationSetBuilder()
                                     .Authorization(TAG_CREATION_DATETIME, 1)
                                     .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
                             /* hw_enforced */
                             AuthorizationSetBuilder()
@@ -238,7 +266,7 @@ TEST_P(DeviceUniqueAttestationTest, Ecdsa) {
                                          .Authorization(TAG_NO_AUTH_REQUIRED)
                                          .EcdsaSigningKey(256)
                                          .Digest(Digest::SHA_2_256)
                                          .Authorization(TAG_CREATION_DATETIME, 1))));
                                          .Authorization(TAG_INCLUDE_UNIQUE_ID))));

    hidl_vec<hidl_vec<uint8_t>> cert_chain;
    HidlBuf challenge("challenge");
@@ -250,15 +278,14 @@ TEST_P(DeviceUniqueAttestationTest, Ecdsa) {
                                        .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
                                &cert_chain)));

    EXPECT_EQ(1U, cert_chain.size());
    EXPECT_EQ(2U, cert_chain.size());
    if (dumpAttestations) dumpContent(bin2hex(cert_chain[0]));
    auto [err, attestation] = parse_attestation_record(cert_chain[0]);
    EXPECT_EQ(ErrorCode::OK, err);
    ASSERT_EQ(ErrorCode::OK, err);

    check_attestation_record(attestation, challenge,
            /* sw_enforced */
                             AuthorizationSetBuilder()
                                     .Authorization(TAG_CREATION_DATETIME, 1)
                                     .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
            AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
            /* hw_enforced */
            AuthorizationSetBuilder()
                    .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
@@ -276,3 +303,17 @@ INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest);

}  // namespace test
}  // namespace android::hardware::keymaster::V4_1

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    for (int i = 1; i < argc; ++i) {
        if (argv[i][0] == '-') {
            if (std::string(argv[i]) == "--dump_attestations") {
                dumpAttestations = true;
            }
        }
    }
    int status = RUN_ALL_TESTS();
    ALOGI("Test result = %d", status);
    return status;
}
+44 −0
Original line number Diff line number Diff line
@@ -452,6 +452,10 @@ TEST_P(SensorsHidlTest, InjectSensorEventData) {
    for (const auto& s : sensors) {
        auto events = callback.getEvents(s.sensorHandle);
        auto lastEvent = events.back();
        SCOPED_TRACE(::testing::Message()
                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                     << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
                     << " name=" << s.name);

        // Verify that only a single event has been received
        ASSERT_EQ(events.size(), 1);
@@ -578,6 +582,12 @@ void SensorsHidlTest::runFlushTest(const std::vector<SensorInfoType>& sensors, b

        // Flush the sensor
        for (int32_t i = 0; i < flushCalls; i++) {
            SCOPED_TRACE(::testing::Message()
                         << "Flush " << i << "/" << flushCalls << ": "
                         << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                         << sensor.sensorHandle << std::dec
                         << " type=" << static_cast<int>(sensor.type) << " name=" << sensor.name);

            Result flushResult = flush(sensor.sensorHandle);
            ASSERT_EQ(flushResult, expectedResponse);
        }
@@ -595,6 +605,10 @@ void SensorsHidlTest::runFlushTest(const std::vector<SensorInfoType>& sensors, b

    // Check that the correct number of flushes are present for each sensor
    for (const SensorInfoType& sensor : sensors) {
        SCOPED_TRACE(::testing::Message()
                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
                     << " name=" << sensor.name);
        ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount);
    }
}
@@ -643,6 +657,11 @@ TEST_P(SensorsHidlTest, Batch) {

    activateAllSensors(false /* enable */);
    for (const SensorInfoType& sensor : getSensorsList()) {
        SCOPED_TRACE(::testing::Message()
                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
                     << " name=" << sensor.name);

        // Call batch on inactive sensor
        // One shot sensors have minDelay set to -1 which is an invalid
        // parameter. Use 0 instead to avoid errors.
@@ -675,6 +694,11 @@ TEST_P(SensorsHidlTest, Activate) {

    // Verify that sensor events are generated when activate is called
    for (const SensorInfoType& sensor : getSensorsList()) {
        SCOPED_TRACE(::testing::Message()
                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
                     << " name=" << sensor.name);

        batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */);
        ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);

@@ -722,6 +746,10 @@ TEST_P(SensorsHidlTest, NoStaleEvents) {
    // Save the last received event for each sensor
    std::map<int32_t, int64_t> lastEventTimestampMap;
    for (const SensorInfoType& sensor : sensors) {
        SCOPED_TRACE(::testing::Message()
                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
                     << " name=" << sensor.name);
        // Some on-change sensors may not report an event without stimulus
        if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) {
            ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
@@ -742,6 +770,11 @@ TEST_P(SensorsHidlTest, NoStaleEvents) {
    getEnvironment()->unregisterCallback();

    for (const SensorInfoType& sensor : sensors) {
        SCOPED_TRACE(::testing::Message()
                     << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                     << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
                     << " name=" << sensor.name);

        // Skip sensors that did not previously report an event
        if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
            continue;
@@ -764,6 +797,12 @@ void SensorsHidlTest::checkRateLevel(const SensorInfoType& sensor, int32_t direc
                                     RateLevel rateLevel) {
    configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel,
                       [&](Result result, int32_t reportToken) {
                           SCOPED_TRACE(::testing::Message()
                                        << " handle=0x" << std::hex << std::setw(8)
                                        << std::setfill('0') << sensor.sensorHandle << std::dec
                                        << " type=" << static_cast<int>(sensor.type)
                                        << " name=" << sensor.name);

                           if (isDirectReportRateSupported(sensor, rateLevel)) {
                               ASSERT_EQ(result, Result::OK);
                               if (rateLevel != RateLevel::STOP) {
@@ -821,6 +860,11 @@ void SensorsHidlTest::verifyRegisterDirectChannel(

void SensorsHidlTest::verifyConfigure(const SensorInfoType& sensor, SharedMemType memType,
                                      int32_t directChannelHandle, bool supportsAnyDirectChannel) {
    SCOPED_TRACE(::testing::Message()
                 << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                 << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
                 << " name=" << sensor.name);

    if (isDirectChannelTypeSupported(sensor, memType)) {
        // Verify that each rate level is properly supported
        checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);