diff --git a/audio/4.0/Android.bp b/audio/4.0/Android.bp index 862c71117c..bc695c852f 100644 --- a/audio/4.0/Android.bp +++ b/audio/4.0/Android.bp @@ -3,6 +3,8 @@ hidl_interface { name: "android.hardware.audio@4.0", root: "android.hardware", + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, vndk: { enabled: true, }, diff --git a/audio/common/2.0/Android.bp b/audio/common/2.0/Android.bp index bd3b069ac7..56b43ffce0 100644 --- a/audio/common/2.0/Android.bp +++ b/audio/common/2.0/Android.bp @@ -3,6 +3,8 @@ hidl_interface { name: "android.hardware.audio.common@2.0", root: "android.hardware", + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, vndk: { enabled: true, }, diff --git a/audio/common/4.0/Android.bp b/audio/common/4.0/Android.bp index c01c486829..e4676ec1f5 100644 --- a/audio/common/4.0/Android.bp +++ b/audio/common/4.0/Android.bp @@ -3,6 +3,8 @@ hidl_interface { name: "android.hardware.audio.common@4.0", root: "android.hardware", + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, vndk: { enabled: true, }, diff --git a/audio/effect/2.0/Android.bp b/audio/effect/2.0/Android.bp index d4482c2082..7b37260a27 100644 --- a/audio/effect/2.0/Android.bp +++ b/audio/effect/2.0/Android.bp @@ -3,6 +3,8 @@ hidl_interface { name: "android.hardware.audio.effect@2.0", root: "android.hardware", + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, vndk: { enabled: true, }, diff --git a/audio/effect/4.0/Android.bp b/audio/effect/4.0/Android.bp index 8c1900f1fe..2242d6d76e 100644 --- a/audio/effect/4.0/Android.bp +++ b/audio/effect/4.0/Android.bp @@ -3,6 +3,8 @@ hidl_interface { name: "android.hardware.audio.effect@4.0", root: "android.hardware", + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, vndk: { enabled: true, }, diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal index 1f69f09b5b..e699fd0d1b 100644 --- a/automotive/evs/1.1/types.hal +++ b/automotive/evs/1.1/types.hal @@ -105,6 +105,10 @@ enum EvsEventType : uint32_t { * Master role has become available */ MASTER_RELEASED, + /** + * Any other erroneous streaming events + */ + STREAM_ERROR, }; /** diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 6a386c3080..8b68fd6f0a 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -2262,6 +2262,7 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { // Allocate buffers to use hidl_vec buffers; + buffers.resize(kBuffersToHold); for (auto i = 0; i < kBuffersToHold; ++i) { unsigned pixelsPerLine; buffer_handle_t memHandle = nullptr; diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index a4fd6415ed..d9ac239f62 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -15,12 +15,10 @@ cc_defaults { name: "vhal_v2_0_defaults", shared_libs: [ - "libbinder_ndk", "libhidlbase", "liblog", "libutils", "android.hardware.automotive.vehicle@2.0", - "carwatchdog_aidl_interface-ndk_platform", ], cflags: [ "-Wall", @@ -29,6 +27,15 @@ cc_defaults { ], } +cc_defaults { + name: "vhal_v2_0_target_defaults", + defaults: ["vhal_v2_0_defaults"], + shared_libs: [ + "libbinder_ndk", + "carwatchdog_aidl_interface-ndk_platform", + ], +} + cc_library_headers { name: "vhal_v2_0_common_headers", vendor: true, @@ -39,7 +46,7 @@ cc_library_headers { cc_library { name: "android.hardware.automotive.vehicle@2.0-manager-lib", vendor: true, - defaults: ["vhal_v2_0_defaults"], + defaults: ["vhal_v2_0_target_defaults"], srcs: [ "common/src/Obd2SensorStore.cpp", "common/src/SubscriptionManager.cpp", @@ -61,7 +68,7 @@ cc_library { cc_library_static { name: "android.hardware.automotive.vehicle@2.0-default-impl-lib", vendor: true, - defaults: ["vhal_v2_0_defaults"], + defaults: ["vhal_v2_0_target_defaults"], srcs: [ "impl/vhal_v2_0/CommConn.cpp", "impl/vhal_v2_0/EmulatedVehicleConnector.cpp", @@ -97,16 +104,59 @@ cc_library_static { cc_library_static { name: "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib", vendor: true, - defaults: ["vhal_v2_0_defaults"], + defaults: ["vhal_v2_0_target_defaults"], srcs: [ "impl/vhal_v2_0/EmulatedUserHal.cpp", ], } +// Vehicle HAL Server reference impl lib +cc_library_static { + name: "android.hardware.automotive.vehicle@2.0-server-common-lib", + vendor: true, + host_supported: true, + defaults: ["vhal_v2_0_defaults"], + local_include_dirs: ["common/include/vhal_v2_0"], + export_include_dirs: ["common/include"], + srcs: [ + "common/src/Obd2SensorStore.cpp", + "common/src/VehicleObjectPool.cpp", + "common/src/VehicleUtils.cpp", + ], +} + +// Vehicle HAL Server default implementation +cc_library_static { + name: "android.hardware.automotive.vehicle@2.0-server-impl-lib", + vendor: true, + host_supported: true, + defaults: ["vhal_v2_0_defaults"], + local_include_dirs: ["common/include/vhal_v2_0"], + export_include_dirs: ["impl"], + srcs: [ + "impl/vhal_v2_0/EmulatedUserHal.cpp", + "impl/vhal_v2_0/GeneratorHub.cpp", + "impl/vhal_v2_0/JsonFakeValueGenerator.cpp", + "impl/vhal_v2_0/LinearFakeValueGenerator.cpp", + "impl/vhal_v2_0/ProtoMessageConverter.cpp", + "impl/vhal_v2_0/VehicleHalServer.cpp", + ], + whole_static_libs: [ + "android.hardware.automotive.vehicle@2.0-server-common-lib", + ], + static_libs: [ + "android.hardware.automotive.vehicle@2.0-libproto-native", + ], + shared_libs: [ + "libbase", + "libjsoncpp", + ], +} + cc_test { name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests", vendor: true, - defaults: ["vhal_v2_0_defaults"], + defaults: ["vhal_v2_0_target_defaults"], whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"], srcs: [ "tests/RecurrentTimer_test.cpp", @@ -126,7 +176,7 @@ cc_test { cc_test { name: "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests", vendor: true, - defaults: ["vhal_v2_0_defaults"], + defaults: ["vhal_v2_0_target_defaults"], srcs: [ "impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp", ], @@ -140,7 +190,7 @@ cc_test { cc_binary { name: "android.hardware.automotive.vehicle@2.0-service", - defaults: ["vhal_v2_0_defaults"], + defaults: ["vhal_v2_0_target_defaults"], vintf_fragments: [ "android.hardware.automotive.vehicle@2.0-service.xml", ], diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h index b8a606adab..16c33b9d19 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h @@ -1036,6 +1036,22 @@ const ConfigDeclaration kVehicleProperties[]{ .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, }, + { + .config = + { + .prop = toInt(VehicleProperty::CREATE_USER), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + }, + { + .config = + { + .prop = toInt(VehicleProperty::REMOVE_USER), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + }, { .config = { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp index d744a06d40..ea38cb3941 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp @@ -30,6 +30,8 @@ namespace impl { constexpr int INITIAL_USER_INFO = static_cast(VehicleProperty::INITIAL_USER_INFO); constexpr int SWITCH_USER = static_cast(VehicleProperty::SWITCH_USER); +constexpr int CREATE_USER = static_cast(VehicleProperty::CREATE_USER); +constexpr int REMOVE_USER = static_cast(VehicleProperty::REMOVE_USER); constexpr int USER_IDENTIFICATION_ASSOCIATION = static_cast(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION); @@ -37,6 +39,8 @@ bool EmulatedUserHal::isSupported(int32_t prop) { switch (prop) { case INITIAL_USER_INFO: case SWITCH_USER: + case CREATE_USER: + case REMOVE_USER: case USER_IDENTIFICATION_ASSOCIATION: return true; default: @@ -53,6 +57,11 @@ android::base::Result> EmulatedUserHal::onSetP return onSetInitialUserInfoResponse(value); case SWITCH_USER: return onSetSwitchUserResponse(value); + case CREATE_USER: + return onSetCreateUserResponse(value); + case REMOVE_USER: + ALOGI("REMOVE_USER is FYI only, nothing to do..."); + return {}; case USER_IDENTIFICATION_ASSOCIATION: return onSetUserIdentificationAssociation(value); default: @@ -62,32 +71,44 @@ android::base::Result> EmulatedUserHal::onSetP } android::base::Result> EmulatedUserHal::onGetProperty( - int32_t prop) { - ALOGV("onGetProperty(%d)", prop); - switch (prop) { + const VehiclePropValue& value) { + ALOGV("onGetProperty(%s)", toString(value).c_str()); + switch (value.prop) { case INITIAL_USER_INFO: case SWITCH_USER: - ALOGE("onGetProperty(): %d is only supported on SET", prop); + case CREATE_USER: + case REMOVE_USER: + ALOGE("onGetProperty(): %d is only supported on SET", value.prop); return android::base::Error(static_cast(StatusCode::INVALID_ARG)) << "only supported on SET"; case USER_IDENTIFICATION_ASSOCIATION: - if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) { - ALOGI("onGetProperty(%d): returning %s", prop, - toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str()); - auto value = std::unique_ptr( - new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd)); - return value; - } - ALOGE("onGetProperty(%d): USER_IDENTIFICATION_ASSOCIATION not set by lshal", prop); - return android::base::Error(static_cast(StatusCode::NOT_AVAILABLE)) - << "not set by lshal"; + return onGetUserIdentificationAssociation(value); default: - ALOGE("onGetProperty(): %d is not supported", prop); + ALOGE("onGetProperty(): %d is not supported", value.prop); return android::base::Error(static_cast(StatusCode::INVALID_ARG)) << "not supported by User HAL"; } } +android::base::Result> +EmulatedUserHal::onGetUserIdentificationAssociation(const VehiclePropValue& value) { + if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) { + ALOGI("get(USER_IDENTIFICATION_ASSOCIATION): returning %s", + toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str()); + auto newValue = std::unique_ptr( + new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd)); + // Must use the same requestId + if (value.value.int32Values.size() > 0) { + newValue->value.int32Values[0] = value.value.int32Values[0]; + } else { + ALOGE("get(USER_IDENTIFICATION_ASSOCIATION): no requestId on %s", + toString(value).c_str()); + } + return newValue; + } + return defaultUserIdentificationAssociation(value); +} + android::base::Result> EmulatedUserHal::onSetInitialUserInfoResponse(const VehiclePropValue& value) { if (value.value.int32Values.size() == 0) { @@ -147,6 +168,20 @@ android::base::Result> EmulatedUserHal::onSetS return sendUserHalResponse(std::move(mSwitchUserResponseFromCmd), requestId); } + if (value.value.int32Values.size() > 1) { + auto messageType = static_cast(value.value.int32Values[1]); + switch (messageType) { + case SwitchUserMessageType::LEGACY_ANDROID_SWITCH: + ALOGI("request is LEGACY_ANDROID_SWITCH; ignoring it"); + return {}; + case SwitchUserMessageType::ANDROID_POST_SWITCH: + ALOGI("request is ANDROID_POST_SWITCH; ignoring it"); + return {}; + default: + break; + } + } + // Returns default response auto updatedValue = std::unique_ptr(new VehiclePropValue); updatedValue->prop = SWITCH_USER; @@ -162,6 +197,41 @@ android::base::Result> EmulatedUserHal::onSetS return updatedValue; } +android::base::Result> EmulatedUserHal::onSetCreateUserResponse( + const VehiclePropValue& value) { + if (value.value.int32Values.size() == 0) { + ALOGE("set(CREATE_USER): no int32values, ignoring it: %s", toString(value).c_str()); + return android::base::Error(static_cast(StatusCode::INVALID_ARG)) + << "no int32values on " << toString(value); + } + + if (value.areaId != 0) { + ALOGD("set(CREATE_USER) called from lshal; storing it: %s", toString(value).c_str()); + mCreateUserResponseFromCmd.reset(new VehiclePropValue(value)); + return {}; + } + ALOGD("set(CREATE_USER) called from Android: %s", toString(value).c_str()); + + int32_t requestId = value.value.int32Values[0]; + if (mCreateUserResponseFromCmd != nullptr) { + ALOGI("replying CREATE_USER with lshal value: %s", + toString(*mCreateUserResponseFromCmd).c_str()); + return sendUserHalResponse(std::move(mCreateUserResponseFromCmd), requestId); + } + + // Returns default response + auto updatedValue = std::unique_ptr(new VehiclePropValue); + updatedValue->prop = CREATE_USER; + updatedValue->timestamp = elapsedRealtimeNano(); + updatedValue->value.int32Values.resize(2); + updatedValue->value.int32Values[0] = requestId; + updatedValue->value.int32Values[1] = (int32_t)CreateUserStatus::SUCCESS; + + ALOGI("no lshal response; replying with SUCCESS: %s", toString(*updatedValue).c_str()); + + return updatedValue; +} + android::base::Result> EmulatedUserHal::onSetUserIdentificationAssociation(const VehiclePropValue& value) { if (value.value.int32Values.size() == 0) { @@ -190,16 +260,14 @@ EmulatedUserHal::onSetUserIdentificationAssociation(const VehiclePropValue& valu } // Returns default response - auto updatedValue = std::unique_ptr(new VehiclePropValue); - updatedValue->prop = USER_IDENTIFICATION_ASSOCIATION; - updatedValue->timestamp = elapsedRealtimeNano(); - updatedValue->value.int32Values.resize(1); - updatedValue->value.int32Values[0] = requestId; - updatedValue->value.stringValue = "Response not set by LSHAL"; + return defaultUserIdentificationAssociation(value); +} - ALOGI("no lshal response; replying with an error message: %s", toString(*updatedValue).c_str()); - - return updatedValue; +android::base::Result> +EmulatedUserHal::defaultUserIdentificationAssociation(const VehiclePropValue& request) { + // TODO(b/159498909): return a response with NOT_ASSOCIATED_ANY_USER for all requested types + ALOGE("no lshal response for %s; replying with NOT_AVAILABLE", toString(request).c_str()); + return android::base::Error(static_cast(StatusCode::NOT_AVAILABLE)) << "not set by lshal"; } android::base::Result> EmulatedUserHal::sendUserHalResponse( @@ -247,6 +315,12 @@ void EmulatedUserHal::dump(int fd, std::string indent) { } else { dprintf(fd, "%sNo SwitchUser response\n", indent.c_str()); } + if (mCreateUserResponseFromCmd != nullptr) { + dprintf(fd, "%sCreateUser response: %s\n", indent.c_str(), + toString(*mCreateUserResponseFromCmd).c_str()); + } else { + dprintf(fd, "%sNo CreateUser response\n", indent.c_str()); + } if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) { dprintf(fd, "%sSetUserIdentificationAssociation response: %s\n", indent.c_str(), toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str()); diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h index 3168d75d44..db2f117e3e 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.h @@ -58,7 +58,8 @@ class EmulatedUserHal { * * @return property value and StatusCode */ - android::base::Result> onGetProperty(int32_t prop); + android::base::Result> onGetProperty( + const VehiclePropValue& value); /** * Shows the User HAL emulation help. @@ -105,17 +106,37 @@ class EmulatedUserHal { const VehiclePropValue& value); /** - * Used to emulate USER_IDENTIFICATION_ASSOCIATION - see onSetInitialUserInfoResponse() for + * Used to emulate CREATE_USER - see onSetInitialUserInfoResponse() for usage. + */ + android::base::Result> onSetCreateUserResponse( + const VehiclePropValue& value); + + /** + * Used to emulate set USER_IDENTIFICATION_ASSOCIATION - see onSetInitialUserInfoResponse() for * usage. */ android::base::Result> onSetUserIdentificationAssociation( const VehiclePropValue& value); + /** + * Used to emulate get USER_IDENTIFICATION_ASSOCIATION - see onSetInitialUserInfoResponse() for + * usage. + */ + android::base::Result> onGetUserIdentificationAssociation( + const VehiclePropValue& value); + + /** + * Creates a default USER_IDENTIFICATION_ASSOCIATION when it was not set by lshal. + */ + android::base::Result> defaultUserIdentificationAssociation( + const VehiclePropValue& request); + android::base::Result> sendUserHalResponse( std::unique_ptr response, int32_t requestId); std::unique_ptr mInitialUserResponseFromCmd; std::unique_ptr mSwitchUserResponseFromCmd; + std::unique_ptr mCreateUserResponseFromCmd; std::unique_ptr mSetUserIdentificationAssociationResponseFromCmd; }; diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp index 9cfcc1c605..a0b566d1ee 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp @@ -153,7 +153,7 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get( default: if (mEmulatedUserHal != nullptr && mEmulatedUserHal->isSupported(propId)) { ALOGI("get(): getting value for prop %d from User HAL", propId); - const auto& ret = mEmulatedUserHal->onGetProperty(propId); + const auto& ret = mEmulatedUserHal->onGetProperty(requestedPropValue); if (!ret.ok()) { ALOGE("get(): User HAL returned error: %s", ret.error().message().c_str()); *outStatus = StatusCode(ret.error().code()); diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp index 31ba8ab18a..c5b9ed6b0a 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp @@ -16,6 +16,7 @@ cc_library_static { name: "android.hardware.automotive.vehicle@2.0-libproto-native", vendor: true, + host_supported: true, proto: { export_proto_headers: true, type: "lite", diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal index 341aae79cd..f7a42e959b 100644 --- a/automotive/vehicle/2.0/types.hal +++ b/automotive/vehicle/2.0/types.hal @@ -2532,23 +2532,23 @@ enum VehicleProperty : int32_t { * * int32[0]: 42 // must match the request id from the request * int32[1]: 2 // action = InitialUserInfoResponseAction::CREATE - * int32[2]: -1 // userToSwitchOrCreate.userId (not used as user will be created) + * int32[2]: -10000 // userToSwitchOrCreate.userId (not used as user will be created) * int32[3]: 8 // userToSwitchOrCreate.flags = ADMIN - * string: "||Owner" // userLocales + separator + userNameToCreate + * string: "||Owner" // userLocales + separator + userNameToCreate * * Notice the string value represents multiple values, separated by ||. The first value is the * (optional) system locales for the user to be created (in this case, it's empty, meaning it * will use Android's default value), while the second value is the (also optional) name of the * to user to be created (when the type of response is InitialUserInfoResponseAction:CREATE). * For example, to create the same "Owner" user with "en-US" and "pt-BR" locales, the string - * value of the response would be "en-US,pt-BR||Owner". + * value of the response would be "en-US,pt-BR||Owner". As such, neither the locale nor the + * name can have || on it, although a single | is fine. * * NOTE: if the HAL doesn't support user management, then it should not define this property, * which in turn would disable the other user-related properties (for example, the Android * system would never issue them and user-related requests from the HAL layer would be ignored - * by the Android System). But if it supports user management, then it must support all - * user-related properties (INITIAL_USER_INFO, SWITCH_USER, CREATE_USER, REMOVE_USER, - * and USER_IDENTIFICATION_ASSOCIATION). + * by the Android System). But if it supports user management, then it must support all core + * user-related properties (INITIAL_USER_INFO, SWITCH_USER, CREATE_USER, and REMOVE_USER). * * @change_mode VehiclePropertyChangeMode:ON_CHANGE * @access VehiclePropertyAccess:READ_WRITE @@ -2627,7 +2627,7 @@ enum VehicleProperty : int32_t { * int32[5]: 0 // current user flags (none) * int32[6]: 3 // number of users * int32[7]: 0 // 1st user (user 0) - * int32[8]: 0 // 1st user flags (none) + * int32[8]: 1 // 1st user flags (SYSTEM) * int32[9]: 10 // 2nd user (user 10) * int32[10]: 0 // 2nd user flags (none) * int32[11]: 11 // 3rd user (user 11) @@ -2661,7 +2661,7 @@ enum VehicleProperty : int32_t { * identified the user as A. * * The HAL makes this request by a property change event (passing a negative request id), and - * the Android system will response by issuye an ANDROID_POST_SWITCH call which the same + * the Android system will response by issue an ANDROID_POST_SWITCH call which the same * request id. * * For example, if the current foreground Android user is 10 and the HAL asked it to switch to @@ -2705,7 +2705,7 @@ enum VehicleProperty : int32_t { * in the response are different (as the current user didn't change to the target). * 3. If a new switch request is made before the HAL responded to the previous one or before * the user was unlocked, then the ANDROID_POST_SWITCH request is not made. For example, - * the driver could accidentally switch to the wrong user which has lock crentials, then + * the driver could accidentally switch to the wrong user which has lock credentials, then * switch to the right one before entering the credentials. * * The HAL can update its internal state once it receives this request, but it doesn't need to @@ -2818,6 +2818,10 @@ enum VehicleProperty : int32_t { * Property used to associate (or query the association) the current user with vehicle-specific * identification mechanisms (such as key FOB). * + * This is an optional user management property - the OEM could still support user management + * without defining it. In fact, this property could be used without supporting the core + * user-related functions described on INITIAL_USER_INFO. + * * 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, returning a VehiclePropValue @@ -4277,6 +4281,16 @@ enum UserFlags: int32_t { * Admin users have additional privileges such as permission to create other users. */ ADMIN = 0x08, + + /** + * Disabled users are marked for deletion. + */ + DISABLED = 0x10, + + /** + * Profile user is a profile of another user. + */ + PROFILE = 0x20, }; /** @@ -4291,10 +4305,16 @@ struct UsersInfo { /** The current foreground user. */ UserInfo currentUser; - /** Number of existing users (includes the current user). */ + /** + * Number of existing users; includes the current user, recently removed users (with DISABLED + * flag), and profile users (with PROFILE flag). + */ int32_t numberUsers; - /** List of existing users (includes the current user). */ + /** + * List of existing users; includes the current user, recently removed users (with DISABLED + * flag), and profile users (with PROFILE flag). + */ vec existingUsers; }; @@ -4370,16 +4390,16 @@ struct InitialUserInfoResponse { */ UserInfo userToSwitchOrCreate; - /** - * Name of the user that should be created. - */ - string userNameToCreate; - /** * System locales of the initial user (value will be passed as-is to * android.provider.Settings.System.SYSTEM_LOCALES) */ string userLocales; + + /** + * Name of the user that should be created. + */ + string userNameToCreate; }; /** diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp index 7ac44a4159..78f93af0d3 100644 --- a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp +++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp @@ -28,6 +28,7 @@ #include #include #include +#include using android::sp; using android::hardware::hidl_vec; @@ -144,7 +145,10 @@ class FaceHidlTest : public ::testing::TestWithParam { ASSERT_EQ(Status::OK, static_cast(ret2)); } - void TearDown() override {} + void TearDown() override { + // Hack to allow the asynchronous operations to finish on time. + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } sp mService; sp mCallback; diff --git a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp index bdbf72dea2..6093caaf04 100644 --- a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp +++ b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp @@ -49,7 +49,7 @@ static const uint32_t kTimeout = 3; static const std::chrono::seconds kTimeoutInSeconds = std::chrono::seconds(kTimeout); static const uint32_t kGroupId = 99; static std::string kTmpDir = ""; -static const uint32_t kIterations = 1000; +static const uint32_t kIterations = 10; // Wait for a callback to occur (signaled by the given future) up to the // provided timeout. If the future is invalid or the callback does not come diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp index 463ed849f6..e9f867f5f0 100644 --- a/bluetooth/1.0/vts/functional/Android.bp +++ b/bluetooth/1.0/vts/functional/Android.bp @@ -26,4 +26,5 @@ cc_test { "general-tests", "vts", ], + disable_framework: true, } diff --git a/camera/device/3.2/ICameraDeviceCallback.hal b/camera/device/3.2/ICameraDeviceCallback.hal index dec3bd88c6..206a649da3 100644 --- a/camera/device/3.2/ICameraDeviceCallback.hal +++ b/camera/device/3.2/ICameraDeviceCallback.hal @@ -87,15 +87,19 @@ interface ICameraDeviceCallback { * ERROR_RESULT message. * * If an output buffer cannot be filled, its status field must be set to - * STATUS_ERROR. In addition, notify() must be called with a ERROR_BUFFER - * message. + * STATUS_ERROR. In this case, notify() isn't required to be called with + * an ERROR_BUFFER message. The framework will simply treat the notify() + * call with ERROR_BUFFER as a no-op, and derive whether and when to notify + * the application of buffer loss based on the buffer status and whether or not + * the entire capture has failed. * * If the entire capture has failed, then this method still needs to be * called to return the output buffers to the framework. All the buffer * statuses must be STATUS_ERROR, and the result metadata must be an * empty buffer. In addition, notify() must be called with a ERROR_REQUEST * message. In this case, individual ERROR_RESULT/ERROR_BUFFER messages - * must not be sent. + * must not be sent. Note that valid partial results are still allowed + * as long as the final result metadata fails to be generated. * * Performance requirements: * diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp index d878deb03d..06ad7e963c 100644 --- a/camera/device/3.2/default/convert.cpp +++ b/camera/device/3.2/default/convert.cpp @@ -38,7 +38,7 @@ bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst) { } const uint8_t* data = src.data(); - // sanity check the size of CameraMetadata match underlying camera_metadata_t + // check that the size of CameraMetadata match underlying camera_metadata_t if (get_camera_metadata_size((camera_metadata_t*)data) != src.size()) { ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__); return false; diff --git a/camera/provider/2.4/vts/functional/AndroidTest.xml b/camera/provider/2.4/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..3000c0e3a6 --- /dev/null +++ b/camera/provider/2.4/vts/functional/AndroidTest.xml @@ -0,0 +1,33 @@ + + + + diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index f6860cfe7f..f235235ab7 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -843,7 +843,7 @@ public: void verifyRequestTemplate(const camera_metadata_t* metadata, RequestTemplate requestTemplate); - bool isDepthOnly(camera_metadata_t* staticMeta); + static bool isDepthOnly(const camera_metadata_t* staticMeta); static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta, std::vector &outputStreams, @@ -1894,7 +1894,7 @@ TEST_P(CameraHidlTest, getCameraDeviceInterface) { } // Verify that the device resource cost can be retrieved and the values are -// sane. +// correct. TEST_P(CameraHidlTest, getResourceCost) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); @@ -2544,7 +2544,7 @@ TEST_P(CameraHidlTest, sendCommandSmoothZoom) { } } -// Basic sanity tests related to camera parameters. +// Basic correctness tests related to camera parameters. TEST_P(CameraHidlTest, getSetParameters) { hidl_vec cameraDeviceNames = getCameraDeviceNames(mProvider); @@ -5537,9 +5537,22 @@ static Size getMinSize(Size a, Size b) { // TODO: Add more combinations Status CameraHidlTest::getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta, std::vector* outputStreams) { - if (nullptr == staticMeta) { + if (nullptr == staticMeta || nullptr == outputStreams) { return Status::ILLEGAL_ARGUMENT; } + + if (isDepthOnly(staticMeta)) { + Size y16MaxSize(640, 480); + Size maxAvailableY16Size; + getMaxOutputSizeForFormat(staticMeta, PixelFormat::Y16, &maxAvailableY16Size); + Size y16ChosenSize = getMinSize(y16MaxSize, maxAvailableY16Size); + AvailableStream y16Stream = {.width = y16ChosenSize.width, + .height = y16ChosenSize.height, + .format = static_cast(PixelFormat::Y16)}; + outputStreams->push_back(y16Stream); + return Status::OK; + } + Size yuvMaxSize(1280, 720); Size jpegMaxSize(1920, 1440); Size maxAvailableYuvSize; @@ -6296,7 +6309,7 @@ void CameraHidlTest::configureOfflineStillStream(const std::string &name, ASSERT_TRUE(ret.isOk()); } -bool CameraHidlTest::isDepthOnly(camera_metadata_t* staticMeta) { +bool CameraHidlTest::isDepthOnly(const camera_metadata_t* staticMeta) { camera_metadata_ro_entry scalarEntry; camera_metadata_ro_entry depthEntry; diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal index ed1d31dd57..d720b26e5c 100644 --- a/camera/provider/2.6/ICameraProvider.hal +++ b/camera/provider/2.6/ICameraProvider.hal @@ -61,6 +61,12 @@ interface ICameraProvider extends @2.5::ICameraProvider { * outputs, stream combinations mentioned above, where YUV is substituted by * Y8 must be also supported. * + * Devices whose capabilities do not include + * ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE, must support + * at least a single Y16 stream, Dataspace::DEPTH with sVGA resolution, + * during concurrent operation. + * Where sVGA - min (max output resolution for the given format, 640 X 480) + * * The camera framework must call this method whenever it gets a * cameraDeviceStatusChange callback adding a new camera device or removing * a camera device known to it. This is so that the camera framework can get new combinations @@ -76,12 +82,16 @@ interface ICameraProvider extends @2.5::ICameraProvider { * configuration settings exposed through camera metadata), should the sum * of resource costs for the combination be <= 100. * - * The lists of camera id combinations returned by this method may contain - * hidden physical camera ids. If a combination does contain hidden physical - * camera ids, the camera framework must be able to open any logical cameras - * that contain these hidden physical camera ids in their - * ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS list, in addition to the other - * camera ids advertised in the combination, for concurrent operation. + * For guaranteed concurrent camera operation, the camera framework must call + * ICameraDevice.open() on all devices (intended for concurrent operation), before configuring + * any streams on them. This gives the camera HAL process an opportunity to potentially + * distribute hardware resources better before stream configuration. + * + * Due to potential hardware constraints around internal switching of physical camera devices, + * a device's complete ZOOM_RATIO_RANGE(if supported), may not apply during concurrent + * operation. If ZOOM_RATIO is supported, camera HALs must ensure ZOOM_RATIO_RANGE of + * [1.0, ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM] is supported by that device, during + * concurrent operation. * * @return status Status code for the operation * @return cameraIds a list of camera id combinations that support diff --git a/current.txt b/current.txt index e2d14083cc..669651625d 100644 --- a/current.txt +++ b/current.txt @@ -588,6 +588,7 @@ c3ec182ce325862b7d79e526f3e170c02cfee1497ed309d7c60d0de4ca636b0b android.hardwar 578f640c653726d58f99c84a7e1bb63862e21ef7cbb4f7d95c3cc62de00dca35 android.hardware.automotive.evs@1.0::IEvsDisplay f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types +2924c3e43858190ee3e2da4c2fb93bba8ae065fe314451f035a7ec52cb80c94a android.hardware.camera.device@3.2::ICameraDeviceCallback # b/155353799 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types 5cf81b1001296fbb3c5b3d275a859244f61cec5fa858d7be9cca46c5b7dfa733 android.hardware.camera.metadata@3.2::types # b/150331548 @@ -657,7 +658,7 @@ ca515ff4b63c80cf5ad7b3395c997c57d6c56157361f6c367d1c96f23cc4860a android.hardwar 87958d728d7c0ee9b9391ab4a072b097914921a7b38f7dc3df427f933a5b528e android.hardware.automotive.evs@1.1::IEvsEnumerator f53b4e8de6209c6d0fa9036005671b34a2f98328b51423d3a5137a43bf42c84d android.hardware.automotive.evs@1.1::IEvsUltrasonicsArray 0460bacbde906a846a3d71b2b7b33d6927cac3ff072e523ffac7853577464406 android.hardware.automotive.evs@1.1::IEvsUltrasonicsArrayStream -3e374b5c4777f959f62a320abb3b9edca8874e24e383dbb19c66d224f151b363 android.hardware.automotive.evs@1.1::types +f27cf8283e7b953d33dd258734749d2fca9cc63502ea41353060ffa78d8ce9f6 android.hardware.automotive.evs@1.1::types 4e4904c4067dadae974ddf90351f362331dcd04bba1d890d313cc8ba91f68c15 android.hardware.automotive.sv@1.0::ISurroundView2dSession 63336e9d03f545020ff2982ff76d9d8c44fa76ad476293b5ef6732cbbd71e61b android.hardware.automotive.sv@1.0::ISurroundView3dSession b7015428cd52ce8192d13bfcbf2c4455cda3727d57f2aac80d65a1747104f5ac android.hardware.automotive.sv@1.0::ISurroundViewService @@ -676,7 +677,7 @@ eb90c4d366f05a025d1d1a3672f8b4c3e33e420fa387f73f21b264645bfdf845 android.hardwar a718c8a3acaa938de5a57923e8c4625ed7ca051e05a1d930ba6998557d7b57c8 android.hardware.camera.device@3.6::ICameraOfflineSession a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types 02bdf82dba7dce273a554b4474468a8fb1fb4f61ab65da95eb16e080df63fff6 android.hardware.camera.metadata@3.5::types -21086e1c7a2acc0ebe0ff8561b11f3c2009be687a92d79b608a5f00b16c5f598 android.hardware.camera.provider@2.6::ICameraProvider +93cd94e47b22007bbf436c2f5c2703bb7b2859d1b714d6ae15520db55667ba6c android.hardware.camera.provider@2.6::ICameraProvider 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback 1edf7aef68ef3bd577a1175b1462fb82e3e39f01c6915dda61fba121028df283 android.hardware.camera.provider@2.6::types c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas @@ -721,6 +722,7 @@ ee9dc34b9925b8367b1111c72bd6d9d375432735e451572ca5a665d8516a7744 android.hardwar eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback acf84925f8ee0a651f2ec547ac334034de266479b93af5434f6c1f25e66aba96 android.hardware.neuralnetworks@1.3::types e9080d04218e98512b63aace9ff3da52f0130238391f15cbbf7df396a3ec9072 android.hardware.neuralnetworks@1.3::types # b/155508675, b/155662254, b/155238914, b/155660285 +583dc88b41e702e940fd954edda1beb8b4151eab55a5c6d7e69e2781bce84b59 android.hardware.neuralnetworks@1.3::types # b/156918813 b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp index 0d540b7250..94bfb894d4 100644 --- a/gnss/1.1/vts/functional/Android.bp +++ b/gnss/1.1/vts/functional/Android.bp @@ -25,6 +25,7 @@ cc_test { static_libs: [ "android.hardware.gnss@1.0", "android.hardware.gnss@1.1", + "android.hardware.gnss@2.0", "android.hardware.gnss@common-vts-lib", ], shared_libs: [ diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp index 59e18f3642..1cb44c5761 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp @@ -247,3 +247,46 @@ Return GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb( capabilities_cbq_.store(capabilities); return Void(); } + +GnssConstellationType_1_0 GnssHalTest::startLocationAndGetNonGpsConstellation() { + const int kLocationsToAwait = 3; + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + const int location_called_count = gnss_cb_->location_cbq_.calledCount(); + + // Tolerate 1 less sv status to handle edge cases in reporting. + int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", + sv_info_list_cbq_size, kLocationsToAwait, location_called_count); + + // Find first non-GPS constellation to blacklist. Exclude IRNSS in GnssConstellationType_2_0 + // as blacklisting of this constellation is not supported in gnss@2.0. + const int kGnssSvStatusTimeout = 2; + GnssConstellationType_1_0 constellation_to_blacklist = GnssConstellationType_1_0::UNKNOWN; + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_list; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); + for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { + if ((sv_info.v1_0.svFlag & IGnssCallback_2_0::GnssSvFlags::USED_IN_FIX) && + (sv_info.constellation != GnssConstellationType_2_0::UNKNOWN) && + (sv_info.constellation != GnssConstellationType_2_0::IRNSS) && + (sv_info.constellation != GnssConstellationType_2_0::GPS)) { + // found a non-GPS V1_0 constellation + constellation_to_blacklist = Utils::mapConstellationType(sv_info.constellation); + break; + } + } + if (constellation_to_blacklist != GnssConstellationType_1_0::UNKNOWN) { + break; + } + } + + if (constellation_to_blacklist == GnssConstellationType_1_0::UNKNOWN) { + ALOGI("No non-GPS constellations found, constellation blacklist test less effective."); + // Proceed functionally to blacklist something. + constellation_to_blacklist = GnssConstellationType_1_0::GLONASS; + } + return constellation_to_blacklist; +} diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h index a02a9ff4a7..7fbd7350eb 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test.h +++ b/gnss/2.0/vts/functional/gnss_hal_test.h @@ -31,6 +31,9 @@ using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrec using android::hardware::gnss::V1_0::GnssLocationFlags; using android::hardware::gnss::V2_0::IGnss; +using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType; +using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType; + using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation; using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation; @@ -194,6 +197,16 @@ class GnssHalTest : public testing::TestWithParam { */ void SetPositionMode(const int min_interval_msec, const bool low_power_mode); + /* + * startLocationAndGetNonGpsConstellation: + * 1. Start location + * 2. Find and return first non-GPS constellation + * + * Note that location is not stopped in this method. The client should call + * StopAndClearLocations() after the call. + */ + GnssConstellationType_1_0 startLocationAndGetNonGpsConstellation(); + sp gnss_hal_; // GNSS HAL to call into sp gnss_cb_; // Primary callback interface }; diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp index 094c7c1e54..51dcf0d059 100644 --- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp @@ -24,8 +24,6 @@ using android::hardware::hidl_string; using android::hardware::hidl_vec; -using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType; -using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType; using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration; using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration; using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil; @@ -491,31 +489,6 @@ TEST_P(GnssHalTest, GetLocationLowPower) { StopAndClearLocations(); } -/* - * MapConstellationType: - * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent - * GnssConstellationType_1_0 type constellation. For constellations that do not have - * an equivalent value, maps to GnssConstellationType_1_0::UNKNOWN - */ -GnssConstellationType_1_0 MapConstellationType(GnssConstellationType_2_0 constellation) { - switch (constellation) { - case GnssConstellationType_2_0::GPS: - return GnssConstellationType_1_0::GPS; - case GnssConstellationType_2_0::SBAS: - return GnssConstellationType_1_0::SBAS; - case GnssConstellationType_2_0::GLONASS: - return GnssConstellationType_1_0::GLONASS; - case GnssConstellationType_2_0::QZSS: - return GnssConstellationType_1_0::QZSS; - case GnssConstellationType_2_0::BEIDOU: - return GnssConstellationType_1_0::BEIDOU; - case GnssConstellationType_2_0::GALILEO: - return GnssConstellationType_1_0::GALILEO; - default: - return GnssConstellationType_1_0::UNKNOWN; - } -} - /* * FindStrongFrequentNonGpsSource: * @@ -555,7 +528,7 @@ IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource( (sv_info.constellation != GnssConstellationType_2_0::GPS)) { ComparableBlacklistedSource source; source.id.svid = sv_info.v1_0.svid; - source.id.constellation = MapConstellationType(sv_info.constellation); + source.id.constellation = Utils::mapConstellationType(sv_info.constellation); const auto& itSignal = mapSignals.find(source); if (itSignal == mapSignals.end()) { @@ -694,7 +667,7 @@ TEST_P(GnssHalTest, BlacklistIndividualSatellites) { hidl_vec sv_info_list; gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { - auto constellation = MapConstellationType(sv_info.constellation); + auto constellation = Utils::mapConstellationType(sv_info.constellation); EXPECT_FALSE((sv_info.v1_0.svid == source_to_blacklist.svid) && (constellation == source_to_blacklist.constellation) && (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)); @@ -736,7 +709,7 @@ TEST_P(GnssHalTest, BlacklistIndividualSatellites) { hidl_vec sv_info_list; gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { - auto constellation = MapConstellationType(sv_info.constellation); + auto constellation = Utils::mapConstellationType(sv_info.constellation); if ((sv_info.v1_0.svid == source_to_blacklist.svid) && (constellation == source_to_blacklist.constellation) && (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) { @@ -752,7 +725,7 @@ TEST_P(GnssHalTest, BlacklistIndividualSatellites) { } /* - * BlacklistConstellation: + * BlacklistConstellationWithLocationOff: * * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding * GnssStatus for any non-GPS constellations. @@ -761,12 +734,11 @@ TEST_P(GnssHalTest, BlacklistIndividualSatellites) { * GnssStatus does not use any constellation but GPS. * 4a & b) Clean up by turning off location, and send in empty blacklist. */ -TEST_P(GnssHalTest, BlacklistConstellation) { +TEST_P(GnssHalTest, BlacklistConstellationWithLocationOff) { if (!IsGnssHalVersion_2_0()) { ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0."); return; } - if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) { ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported."); return; @@ -774,43 +746,12 @@ TEST_P(GnssHalTest, BlacklistConstellation) { const int kLocationsToAwait = 3; - gnss_cb_->location_cbq_.reset(); - StartAndCheckLocations(kLocationsToAwait); - const int location_called_count = gnss_cb_->location_cbq_.calledCount(); + // Find first non-GPS constellation to blacklist + GnssConstellationType_1_0 constellation_to_blacklist = startLocationAndGetNonGpsConstellation(); - // Tolerate 1 less sv status to handle edge cases in reporting. - int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); - EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); - ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)", - sv_info_list_cbq_size, kLocationsToAwait, location_called_count); + // Turns off location + StopAndClearLocations(); - // Find first non-GPS constellation to blacklist. Exclude IRNSS in GnssConstellationType_2_0 - // as blacklisting of this constellation is not supported in gnss@2.0. - const int kGnssSvStatusTimeout = 2; - GnssConstellationType_1_0 constellation_to_blacklist = GnssConstellationType_1_0::UNKNOWN; - for (int i = 0; i < sv_info_list_cbq_size; ++i) { - hidl_vec sv_info_list; - gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); - for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { - if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) && - (sv_info.constellation != GnssConstellationType_2_0::UNKNOWN) && - (sv_info.constellation != GnssConstellationType_2_0::IRNSS) && - (sv_info.constellation != GnssConstellationType_2_0::GPS)) { - // found a non-GPS V1_0 constellation - constellation_to_blacklist = MapConstellationType(sv_info.constellation); - break; - } - } - if (constellation_to_blacklist != GnssConstellationType_1_0::UNKNOWN) { - break; - } - } - - if (constellation_to_blacklist == GnssConstellationType_1_0::UNKNOWN) { - ALOGI("No non-GPS constellations found, constellation blacklist test less effective."); - // Proceed functionally to blacklist something. - constellation_to_blacklist = GnssConstellationType_1_0::GLONASS; - } IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist; source_to_blacklist.constellation = constellation_to_blacklist; source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation @@ -824,6 +765,7 @@ TEST_P(GnssHalTest, BlacklistConstellation) { sources.resize(1); sources[0] = source_to_blacklist; + // setBlacklist when location is off. auto result = gnss_configuration_hal->setBlacklist(sources); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); @@ -835,15 +777,93 @@ TEST_P(GnssHalTest, BlacklistConstellation) { StartAndCheckLocations(kLocationsToAwait); // Tolerate 1 less sv status to handle edge cases in reporting. - sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size, kLocationsToAwait); + const int kGnssSvStatusTimeout = 2; for (int i = 0; i < sv_info_list_cbq_size; ++i) { hidl_vec sv_info_list; gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { - auto constellation = MapConstellationType(sv_info.constellation); + auto constellation = Utils::mapConstellationType(sv_info.constellation); + EXPECT_FALSE((constellation == source_to_blacklist.constellation) && + (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)); + } + } + + // clean up + StopAndClearLocations(); + sources.resize(0); + result = gnss_configuration_hal->setBlacklist(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} + +/* + * BlacklistConstellationWithLocationOn: + * + * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus for any non-GPS constellations. + * 2a & b) Blacklist first non-GPS constellations, and turns off location. + * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus does not use any constellation but GPS. + * 4a & b) Clean up by turning off location, and send in empty blacklist. + */ +TEST_P(GnssHalTest, BlacklistConstellationWithLocationOn) { + if (!IsGnssHalVersion_2_0()) { + ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0."); + return; + } + + if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) { + ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported."); + return; + } + + const int kLocationsToAwait = 3; + + // Find first non-GPS constellation to blacklist + GnssConstellationType_1_0 constellation_to_blacklist = startLocationAndGetNonGpsConstellation(); + + IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist; + source_to_blacklist.constellation = constellation_to_blacklist; + source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation + + auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1(); + ASSERT_TRUE(gnss_configuration_hal_return.isOk()); + sp gnss_configuration_hal = gnss_configuration_hal_return; + ASSERT_NE(gnss_configuration_hal, nullptr); + + hidl_vec sources; + sources.resize(1); + sources[0] = source_to_blacklist; + + // setBlacklist when location is on. + auto result = gnss_configuration_hal->setBlacklist(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + // Turns off location + StopAndClearLocations(); + + // retry and ensure constellation not used + gnss_cb_->sv_info_list_cbq_.reset(); + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + + // Tolerate 1 less sv status to handle edge cases in reporting. + int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size, + kLocationsToAwait); + const int kGnssSvStatusTimeout = 2; + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_list; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); + for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { + auto constellation = Utils::mapConstellationType(sv_info.constellation); EXPECT_FALSE((constellation == source_to_blacklist.constellation) && (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)); } diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp index fd9613b02a..4c6d4439bc 100644 --- a/gnss/common/utils/vts/Android.bp +++ b/gnss/common/utils/vts/Android.bp @@ -29,6 +29,7 @@ cc_library_static { export_include_dirs: ["include"], shared_libs: [ "android.hardware.gnss@1.0", + "android.hardware.gnss@2.0", "android.hardware.gnss.measurement_corrections@1.0", "android.hardware.gnss.measurement_corrections@1.1", ], diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp index 4b5a50f5bd..9bf68e609f 100644 --- a/gnss/common/utils/vts/Utils.cpp +++ b/gnss/common/utils/vts/Utils.cpp @@ -169,6 +169,31 @@ const MeasurementCorrections_1_1 Utils::getMockMeasurementCorrections_1_1() { return mockCorrections_1_1; } +/* + * MapConstellationType: + * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent + * GnssConstellationType_1_0 type constellation. For constellations that do not have + * an equivalent value, maps to GnssConstellationType_1_0::UNKNOWN + */ +GnssConstellationType_1_0 Utils::mapConstellationType(GnssConstellationType_2_0 constellation) { + switch (constellation) { + case GnssConstellationType_2_0::GPS: + return GnssConstellationType_1_0::GPS; + case GnssConstellationType_2_0::SBAS: + return GnssConstellationType_1_0::SBAS; + case GnssConstellationType_2_0::GLONASS: + return GnssConstellationType_1_0::GLONASS; + case GnssConstellationType_2_0::QZSS: + return GnssConstellationType_1_0::QZSS; + case GnssConstellationType_2_0::BEIDOU: + return GnssConstellationType_1_0::BEIDOU; + case GnssConstellationType_2_0::GALILEO: + return GnssConstellationType_1_0::GALILEO; + default: + return GnssConstellationType_1_0::UNKNOWN; + } +} + } // namespace common } // namespace gnss } // namespace hardware diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h index c3cdd18b77..9c838b290a 100644 --- a/gnss/common/utils/vts/include/Utils.h +++ b/gnss/common/utils/vts/include/Utils.h @@ -18,9 +18,12 @@ #define android_hardware_gnss_common_vts_Utils_H_ #include +#include #include #include +using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType; +using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType; using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation; using namespace android::hardware::gnss::measurement_corrections::V1_0; @@ -44,6 +47,8 @@ struct Utils { bool check_more_accuracies); static const MeasurementCorrections_1_0 getMockMeasurementCorrections(); static const MeasurementCorrections_1_1 getMockMeasurementCorrections_1_1(); + + static GnssConstellationType_1_0 mapConstellationType(GnssConstellationType_2_0 constellation); }; } // namespace common diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl index ccb0690e82..b329cb2d3c 100644 --- a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl +++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl @@ -100,10 +100,11 @@ parcelable PlaneLayout { long totalSizeInBytes; /** - * Horizontal and vertical subsampling. Must be a positive power of 2. + * Horizontal and vertical subsampling. Must be a positive power of 2. A value of 1 + * indicates no subsampling. * * These fields indicate the number of horizontally or vertically adjacent pixels that use - * the same pixel data. A value of 1 indicates no subsampling. + * the same pixel data. */ long horizontalSubsampling; long verticalSubsampling; diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp index dafbbf9c9e..e137afb27a 100644 --- a/graphics/composer/2.1/vts/functional/Android.bp +++ b/graphics/composer/2.1/vts/functional/Android.bp @@ -23,6 +23,10 @@ cc_test { shared_libs: [ "libfmq", "libsync", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.1", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", ], static_libs: [ "android.hardware.graphics.allocator@2.0", @@ -30,13 +34,9 @@ cc_test { "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.1-vts", - "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.0-vts", - "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@2.1-vts", - "android.hardware.graphics.mapper@3.0", "android.hardware.graphics.mapper@3.0-vts", - "android.hardware.graphics.mapper@4.0", "android.hardware.graphics.mapper@4.0-vts", ], header_libs: [ diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index e1a254dee4..d80845f9dd 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -33,6 +33,10 @@ cc_test { "libprocessgroup", "libsync", "libui", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.1", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", ], static_libs: [ "android.hardware.graphics.allocator@2.0", @@ -43,13 +47,9 @@ cc_test { "android.hardware.graphics.composer@2.1-vts", "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.2-vts", - "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.0-vts", - "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@2.1-vts", - "android.hardware.graphics.mapper@3.0", "android.hardware.graphics.mapper@3.0-vts", - "android.hardware.graphics.mapper@4.0", "android.hardware.graphics.mapper@4.0-vts", "libgtest", "librenderengine", diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp index 18ea2aa96c..1ab6b3b88d 100644 --- a/graphics/composer/2.3/vts/functional/Android.bp +++ b/graphics/composer/2.3/vts/functional/Android.bp @@ -24,6 +24,10 @@ cc_test { "libfmq", "libhidlbase", "libsync", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.1", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", ], static_libs: [ "android.hardware.graphics.allocator@2.0", @@ -35,13 +39,9 @@ cc_test { "android.hardware.graphics.composer@2.2-vts", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.3-vts", - "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.0-vts", - "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@2.1-vts", - "android.hardware.graphics.mapper@3.0", "android.hardware.graphics.mapper@3.0-vts", - "android.hardware.graphics.mapper@4.0", "android.hardware.graphics.mapper@4.0-vts", ], header_libs: [ diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp index 9e7cc46c56..d0209b7af3 100644 --- a/graphics/composer/2.4/vts/functional/Android.bp +++ b/graphics/composer/2.4/vts/functional/Android.bp @@ -23,6 +23,10 @@ cc_test { shared_libs: [ "libfmq", "libsync", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@2.1", + "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", ], static_libs: [ "android.hardware.graphics.allocator@2.0", @@ -36,13 +40,9 @@ cc_test { "android.hardware.graphics.composer@2.3-vts", "android.hardware.graphics.composer@2.4", "android.hardware.graphics.composer@2.4-vts", - "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.0-vts", - "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@2.1-vts", - "android.hardware.graphics.mapper@3.0", "android.hardware.graphics.mapper@3.0-vts", - "android.hardware.graphics.mapper@4.0", "android.hardware.graphics.mapper@4.0-vts", ], header_libs: [ diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 27b633a409..6b0d106075 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -414,12 +414,9 @@ void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTi mWriter->validateDisplay(); execute(); - if (mReader->mCompositionChanges.size() != 0) { - GTEST_SUCCEED() << "Composition change requested, skipping test"; - return; - } - ASSERT_EQ(0, mReader->mErrors.size()); + mReader->mCompositionChanges.clear(); + mWriter->presentDisplay(); execute(); ASSERT_EQ(0, mReader->mErrors.size()); @@ -427,8 +424,14 @@ void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTi mWriter->selectLayer(layer); auto handle2 = allocate(); ASSERT_NE(nullptr, handle2); + mWriter->setLayerBuffer(0, handle2, -1); mWriter->setLayerSurfaceDamage(std::vector(1, {0, 0, 10, 10})); + mWriter->validateDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + mReader->mCompositionChanges.clear(); + mWriter->presentDisplay(); execute(); } @@ -490,16 +493,16 @@ void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints( // At this point the refresh rate should have changed already, however in rare // cases the implementation might have missed the deadline. In this case a new // timeline should have been provided. - auto newTimelime = mComposerCallback->takeLastVsyncPeriodChangeTimeline(); + auto newTimeline = mComposerCallback->takeLastVsyncPeriodChangeTimeline(); if (timeline.refreshRequired && refreshMiss) { - EXPECT_TRUE(newTimelime.has_value()); + EXPECT_TRUE(newTimeline.has_value()); } - if (newTimelime.has_value()) { - if (timeline.refreshRequired) { - sendRefreshFrame(&newTimelime.value()); + if (newTimeline.has_value()) { + if (newTimeline->refreshRequired) { + sendRefreshFrame(&newTimeline.value()); } - waitForVsyncPeriodChange(display, newTimelime.value(), constraints.desiredTimeNanos, + waitForVsyncPeriodChange(display, newTimeline.value(), constraints.desiredTimeNanos, vsyncPeriod1, vsyncPeriod2); } diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index 529fb1817a..bb775dc689 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -587,8 +587,8 @@ TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) { static_cast(info.height)}; unique_fd fence; uint8_t* data; - ASSERT_NO_FATAL_FAILURE(data = static_cast( - mGralloc->lock(bufferHandle, info.usage, region, fence.get()))); + ASSERT_NO_FATAL_FAILURE(data = static_cast(mGralloc->lock(bufferHandle, info.usage, + region, fence.release()))); // RGBA_8888 fillRGBA8888(data, info.height, stride * 4, info.width * 4); @@ -596,8 +596,8 @@ TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) { ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); // lock again for reading - ASSERT_NO_FATAL_FAILURE(data = static_cast( - mGralloc->lock(bufferHandle, info.usage, region, fence.get()))); + ASSERT_NO_FATAL_FAILURE(data = static_cast(mGralloc->lock(bufferHandle, info.usage, + region, fence.release()))); ASSERT_NO_FATAL_FAILURE( verifyRGBA8888(bufferHandle, data, info.height, stride * 4, info.width * 4)); @@ -605,6 +605,9 @@ TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) { ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); } +/** + * Test multiple operations associated with different color formats + */ TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) { auto info = mDummyDescriptorInfo; info.format = PixelFormat::YCRCB_420_SP; @@ -624,8 +627,8 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) { unique_fd fence; uint8_t* data; - ASSERT_NO_FATAL_FAILURE(data = static_cast( - mGralloc->lock(bufferHandle, info.usage, region, fence.get()))); + ASSERT_NO_FATAL_FAILURE(data = static_cast(mGralloc->lock(bufferHandle, info.usage, + region, fence.release()))); android_ycbcr yCbCr; int64_t hSubsampling = 0; @@ -647,8 +650,8 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) { ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); // lock again for reading - ASSERT_NO_FATAL_FAILURE(data = static_cast( - mGralloc->lock(bufferHandle, info.usage, region, fence.get()))); + ASSERT_NO_FATAL_FAILURE(data = static_cast(mGralloc->lock(bufferHandle, info.usage, + region, fence.release()))); ASSERT_NO_FATAL_FAILURE( getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling)); @@ -658,6 +661,56 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) { ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); } +TEST_P(GraphicsMapperHidlTest, YV12SubsampleMetadata) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::YV12; + + const native_handle_t* bufferHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE( + bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride)); + + const IMapper::Rect region{0, 0, static_cast(info.width), + static_cast(info.height)}; + unique_fd fence; + ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release())); + + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec)); + std::vector planeLayouts; + ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); + + ASSERT_EQ(3, planeLayouts.size()); + + auto yPlane = planeLayouts[0]; + auto crPlane = planeLayouts[1]; + auto cbPlane = planeLayouts[2]; + + constexpr uint32_t kCbCrSubSampleFactor = 2; + EXPECT_EQ(kCbCrSubSampleFactor, crPlane.horizontalSubsampling); + EXPECT_EQ(kCbCrSubSampleFactor, crPlane.verticalSubsampling); + + EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.horizontalSubsampling); + EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.verticalSubsampling); + + const long chromaSampleWidth = info.width / kCbCrSubSampleFactor; + const long chromaSampleHeight = info.height / kCbCrSubSampleFactor; + + EXPECT_EQ(info.width, yPlane.widthInSamples); + EXPECT_EQ(info.height, yPlane.heightInSamples); + + EXPECT_EQ(chromaSampleWidth, crPlane.widthInSamples); + EXPECT_EQ(chromaSampleHeight, crPlane.heightInSamples); + + EXPECT_EQ(chromaSampleWidth, cbPlane.widthInSamples); + EXPECT_EQ(chromaSampleHeight, cbPlane.heightInSamples); + + EXPECT_LE(crPlane.widthInSamples, crPlane.strideInBytes); + EXPECT_LE(cbPlane.widthInSamples, cbPlane.strideInBytes); + + ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); +} + TEST_P(GraphicsMapperHidlTest, Lock_YV12) { auto info = mDummyDescriptorInfo; info.format = PixelFormat::YV12; @@ -673,8 +726,8 @@ TEST_P(GraphicsMapperHidlTest, Lock_YV12) { unique_fd fence; uint8_t* data; - ASSERT_NO_FATAL_FAILURE(data = static_cast( - mGralloc->lock(bufferHandle, info.usage, region, fence.get()))); + ASSERT_NO_FATAL_FAILURE(data = static_cast(mGralloc->lock(bufferHandle, info.usage, + region, fence.release()))); android_ycbcr yCbCr; int64_t hSubsampling = 0; @@ -696,8 +749,8 @@ TEST_P(GraphicsMapperHidlTest, Lock_YV12) { ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); // lock again for reading - ASSERT_NO_FATAL_FAILURE(data = static_cast( - mGralloc->lock(bufferHandle, info.usage, region, fence.get()))); + ASSERT_NO_FATAL_FAILURE(data = static_cast(mGralloc->lock(bufferHandle, info.usage, + region, fence.release()))); ASSERT_NO_FATAL_FAILURE( getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling)); @@ -722,8 +775,8 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { unique_fd fence; uint8_t* data; - ASSERT_NO_FATAL_FAILURE(data = static_cast( - mGralloc->lock(bufferHandle, info.usage, region, fence.get()))); + ASSERT_NO_FATAL_FAILURE(data = static_cast(mGralloc->lock(bufferHandle, info.usage, + region, fence.release()))); android_ycbcr yCbCr; int64_t hSubsampling = 0; @@ -740,8 +793,8 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); // lock again for reading - ASSERT_NO_FATAL_FAILURE(data = static_cast( - mGralloc->lock(bufferHandle, info.usage, region, fence.get()))); + ASSERT_NO_FATAL_FAILURE(data = static_cast(mGralloc->lock(bufferHandle, info.usage, + region, fence.release()))); ASSERT_NO_FATAL_FAILURE( getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling)); @@ -751,6 +804,90 @@ TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_420_888) { ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); } +TEST_P(GraphicsMapperHidlTest, Lock_RAW10) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::RAW10; + + const native_handle_t* bufferHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate( + info, true, Tolerance::kToleranceUnSupported, &stride)); + if (bufferHandle == nullptr) { + GTEST_SUCCEED() << "RAW10 format is unsupported"; + return; + } + + const IMapper::Rect region{0, 0, static_cast(info.width), + static_cast(info.height)}; + unique_fd fence; + + ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release())); + + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec)); + std::vector planeLayouts; + ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); + + ASSERT_EQ(1, planeLayouts.size()); + auto planeLayout = planeLayouts[0]; + + EXPECT_EQ(0, planeLayout.sampleIncrementInBits); + EXPECT_EQ(1, planeLayout.horizontalSubsampling); + EXPECT_EQ(1, planeLayout.verticalSubsampling); + + ASSERT_EQ(1, planeLayout.components.size()); + auto planeLayoutComponent = planeLayout.components[0]; + + EXPECT_EQ(PlaneLayoutComponentType::RAW, + static_cast(planeLayoutComponent.type.value)); + EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8); + EXPECT_EQ(-1, planeLayoutComponent.sizeInBits); + + ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); +} + +TEST_P(GraphicsMapperHidlTest, Lock_RAW12) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::RAW12; + + const native_handle_t* bufferHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate( + info, true, Tolerance::kToleranceUnSupported, &stride)); + if (bufferHandle == nullptr) { + GTEST_SUCCEED() << "RAW12 format is unsupported"; + return; + } + + const IMapper::Rect region{0, 0, static_cast(info.width), + static_cast(info.height)}; + unique_fd fence; + + ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.release())); + + hidl_vec vec; + ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec)); + std::vector planeLayouts; + ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts)); + + ASSERT_EQ(1, planeLayouts.size()); + auto planeLayout = planeLayouts[0]; + + EXPECT_EQ(0, planeLayout.sampleIncrementInBits); + EXPECT_EQ(1, planeLayout.horizontalSubsampling); + EXPECT_EQ(1, planeLayout.verticalSubsampling); + + ASSERT_EQ(1, planeLayout.components.size()); + auto planeLayoutComponent = planeLayout.components[0]; + + EXPECT_EQ(PlaneLayoutComponentType::RAW, + static_cast(planeLayoutComponent.type.value)); + EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8); + EXPECT_EQ(-1, planeLayoutComponent.sizeInBits); + + ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); +} + /** * Test IMapper::unlock with bad access region */ @@ -1706,6 +1843,84 @@ TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) { mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, vec)); } +/** + * Test get::metadata with cloned native_handle + */ +TEST_P(GraphicsMapperHidlTest, GetMetadataClonedHandle) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + + const auto dataspace = Dataspace::SRGB_LINEAR; + { + hidl_vec metadata; + ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &metadata)); + + Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, metadata); + if (err == Error::UNSUPPORTED) { + GTEST_SUCCEED() << "setting this metadata is unsupported"; + return; + } + ASSERT_EQ(Error::NONE, err); + } + + const native_handle_t* importedHandle; + { + auto clonedHandle = native_handle_clone(bufferHandle); + ASSERT_NO_FATAL_FAILURE(importedHandle = mGralloc->importBuffer(clonedHandle)); + native_handle_close(clonedHandle); + native_handle_delete(clonedHandle); + } + + Dataspace realSpace = Dataspace::UNKNOWN; + { + hidl_vec metadata; + ASSERT_EQ(Error::NONE, + mGralloc->get(importedHandle, gralloc4::MetadataType_Dataspace, &metadata)); + ASSERT_NO_FATAL_FAILURE(gralloc4::decodeDataspace(metadata, &realSpace)); + } + + EXPECT_EQ(dataspace, realSpace); +} + +/** + * Test set::metadata with cloned native_handle + */ +TEST_P(GraphicsMapperHidlTest, SetMetadataClonedHandle) { + const native_handle_t* bufferHandle = nullptr; + ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true)); + + const native_handle_t* importedHandle; + { + auto clonedHandle = native_handle_clone(bufferHandle); + ASSERT_NO_FATAL_FAILURE(importedHandle = mGralloc->importBuffer(clonedHandle)); + native_handle_close(clonedHandle); + native_handle_delete(clonedHandle); + } + + const auto dataspace = Dataspace::SRGB_LINEAR; + { + hidl_vec metadata; + ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &metadata)); + + Error err = mGralloc->set(importedHandle, gralloc4::MetadataType_Dataspace, metadata); + if (err == Error::UNSUPPORTED) { + GTEST_SUCCEED() << "setting this metadata is unsupported"; + return; + } + ASSERT_EQ(Error::NONE, err); + } + + Dataspace realSpace = Dataspace::UNKNOWN; + { + hidl_vec metadata; + ASSERT_EQ(Error::NONE, + mGralloc->get(bufferHandle, gralloc4::MetadataType_Dataspace, &metadata)); + ASSERT_NO_FATAL_FAILURE(gralloc4::decodeDataspace(metadata, &realSpace)); + } + + EXPECT_EQ(dataspace, realSpace); +} + /** * Test IMapper::set(metadata) for constant metadata */ diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl index d7f47e82c0..730b601c69 100644 --- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl +++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl @@ -151,8 +151,8 @@ interface IIdentityCredential { * IntentToRetain = bool * * For the readerSignature parameter, this can either be empty or if non-empty it - * must be a COSE_Sign1 structure with an ECDSA signature over the content of the - * CBOR conforming to the following CDDL: + * must be a COSE_Sign1 where the payload is the bytes of the + * ReaderAuthenticationBytes CBOR defined below: * * ReaderAuthentication = [ * "ReaderAuthentication", @@ -160,16 +160,11 @@ interface IIdentityCredential { * ItemsRequestBytes * ] * - * SessionTranscript = [ - * DeviceEngagementBytes, - * EReaderKeyBytes - * ] + * SessionTranscript = any * - * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement) - * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub) * ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest) * - * EReaderKey.Pub = COSE_Key ; Ephemeral public key provided by reader + * ReaderAuthenticationBytes = #6.24(bstr .cbor ReaderAuthentication) * * The public key corresponding to the key used to made signature, can be found in the * 'x5chain' unprotected header element of the COSE_Sign1 structure (as as described @@ -184,8 +179,12 @@ interface IIdentityCredential { * * If the SessionTranscript CBOR is not empty, the X and Y coordinates of the public * part of the key-pair previously generated by createEphemeralKeyPair() must appear - * somewhere in the bytes of DeviceEngagement structure. Both X and Y should be in - * uncompressed form. If this is not satisfied, the call fails with + * somewhere in the bytes of the CBOR. Each of these coordinates must appear encoded + * with the most significant bits first and use the exact amount of bits indicated by + * the key size of the ephemeral keys. For example, if the ephemeral key is using the + * P-256 curve then the 32 bytes for the X coordinate encoded with the most significant + * bits first must appear somewhere in the CBOR and ditto for the 32 bytes for the Y + * coordinate. If this is not satisfied, the call fails with * STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND. * * @param accessControlProfiles @@ -281,7 +280,7 @@ interface IIdentityCredential { * * @param out mac is empty if signingKeyBlob or the sessionTranscript passed to * startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload - * and the detached content is set to DeviceAuthentication as defined below. + * and the detached content is set to DeviceAuthenticationBytes as defined below. * This code is produced by using the key agreement and key derivation function * from the ciphersuite with the authentication private key and the reader * ephemeral public key to compute a shared message authentication code (MAC) @@ -298,15 +297,12 @@ interface IIdentityCredential { * * DocType = tstr * - * SessionTranscript = [ - * DeviceEngagementBytes, - * EReaderKeyBytes - * ] + * SessionTranscript = any * - * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement) - * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub) * DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces) * + * DeviceAuthenticationBytes = #6.24(bstr .cbor DeviceAuthentication) + * * where * * DeviceNameSpaces = { @@ -356,8 +352,9 @@ interface IIdentityCredential { * * - subjectPublicKeyInfo: must contain attested public key. * - * @param out signingKeyBlob contains an encrypted copy of the newly-generated private - * signing key. + * @param out signingKeyBlob contains an AES-GCM-ENC(storageKey, R, signingKey, docType) + * where signingKey is an EC private key in uncompressed form. That is, the returned + * blob is an encrypted copy of the newly-generated private signing key. * * @return an X.509 certificate for the new signing key, signed by the credential key. */ diff --git a/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl index bd664e86ea..33e25b1adf 100644 --- a/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl +++ b/identity/aidl/android/hardware/identity/IIdentityCredentialStore.aidl @@ -99,7 +99,7 @@ import android.hardware.identity.CipherSuite; * Various fields need to be encoded as precisely-specified byte arrays. Where existing standards * define appropriate encodings, those are used. For example, X.509 certificates. Where new * encodings are needed, CBOR is used. CBOR maps are described in CDDL notation - * (https://tools.ietf.org/html/draft-ietf-cbor-cddl-06). + * (https://tools.ietf.org/html/rfc8610). * * All binder calls in the HAL may return a ServiceSpecificException with statuses from the * STATUS_* integers defined in this interface. Each method states which status can be returned diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl index b7ad283bf8..297fd1d8ec 100644 --- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl +++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl @@ -29,9 +29,27 @@ interface IWritableIdentityCredential { * Gets the certificate chain for credentialKey which can be used to prove the hardware * characteristics to an issuing authority. Must not be called more than once. * + * The following non-optional fields for the X.509 certificate shall be set as follows: + * + * - version: INTEGER 2 (means v3 certificate). + * + * - serialNumber: INTEGER 1 (fixed value: same on all certs). + * + * - signature: must be set to ECDSA. + * + * - subject: CN shall be set to "Android Identity Credential Key". + * + * - issuer: shall be set to "credentialStoreName (credentialStoreAuthorName)" using the + * values returned in HardwareInformation. + * + * - validity: should be from current time and expire at the same time as the + * attestation batch certificate used. + * + * - subjectPublicKeyInfo: must contain attested public key. + * * The certificate chain must be generated using Keymaster Attestation * (see https://source.android.com/security/keystore/attestation) with the - * following additional requirements: + * following additional requirements on the data in the attestation extension: * * - The attestationVersion field in the attestation extension must be at least 3. * @@ -109,7 +127,8 @@ interface IWritableIdentityCredential { * in Tag::ATTESTATION_APPLICATION_ID. This schema is described in * https://developer.android.com/training/articles/security-key-attestation#certificate_schema_attestationid * - * @param attestationChallenge a challenge set by the issuer to ensure freshness. + * @param attestationChallenge a challenge set by the issuer to ensure freshness. If + * this is empty, the call fails with STATUS_INVALID_DATA. * * @return the X.509 certificate chain for the credentialKey */ @@ -250,6 +269,7 @@ interface IWritableIdentityCredential { * CredentialKeys = [ * bstr, ; storageKey, a 128-bit AES key * bstr ; credentialPrivKey, the private key for credentialKey + * ; in uncompressed form * ] * * @param out proofOfProvisioningSignature proves to the IA that the credential was imported diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp index 8a00d221b7..10f9aa5886 100644 --- a/identity/aidl/default/IdentityCredential.cpp +++ b/identity/aidl/default/IdentityCredential.cpp @@ -39,6 +39,10 @@ using ::std::optional; using namespace ::android::hardware::identity; int IdentityCredential::initialize() { + if (credentialData_.size() == 0) { + LOG(ERROR) << "CredentialData is empty"; + return IIdentityCredentialStore::STATUS_INVALID_DATA; + } auto [item, _, message] = cppbor::parse(credentialData_); if (item == nullptr) { LOG(ERROR) << "CredentialData is not valid CBOR: " << message; @@ -164,6 +168,7 @@ ndk::ScopedAStatus IdentityCredential::createAuthChallenge(int64_t* outChallenge } *outChallenge = challenge; + authChallenge_ = challenge; return ndk::ScopedAStatus::ok(); } @@ -223,7 +228,8 @@ bool checkUserAuthentication(const SecureAccessControlProfile& profile, } if (authToken.challenge != int64_t(authChallenge)) { - LOG(ERROR) << "Challenge in authToken doesn't match the challenge we created"; + LOG(ERROR) << "Challenge in authToken (" << uint64_t(authToken.challenge) << ") " + << "doesn't match the challenge we created (" << authChallenge << ")"; return false; } return true; @@ -314,13 +320,16 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval( } const vector& itemsRequestBytes = itemsRequest; - vector dataThatWasSigned = cppbor::Array() - .add("ReaderAuthentication") - .add(sessionTranscriptItem_->clone()) - .add(cppbor::Semantic(24, itemsRequestBytes)) - .encode(); + vector encodedReaderAuthentication = + cppbor::Array() + .add("ReaderAuthentication") + .add(sessionTranscriptItem_->clone()) + .add(cppbor::Semantic(24, itemsRequestBytes)) + .encode(); + vector encodedReaderAuthenticationBytes = + cppbor::Semantic(24, encodedReaderAuthentication).encode(); if (!support::coseCheckEcDsaSignature(readerSignature, - dataThatWasSigned, // detached content + encodedReaderAuthenticationBytes, // detached content readerPublicKey.value())) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED, @@ -341,28 +350,6 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval( // // We do this by just searching for the X and Y coordinates. if (sessionTranscript.size() > 0) { - const cppbor::Array* array = sessionTranscriptItem_->asArray(); - if (array == nullptr || array->size() != 2) { - return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( - IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND, - "SessionTranscript is not an array with two items")); - } - const cppbor::Semantic* taggedEncodedDE = (*array)[0]->asSemantic(); - if (taggedEncodedDE == nullptr || taggedEncodedDE->value() != 24) { - return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( - IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND, - "First item in SessionTranscript array is not a " - "semantic with value 24")); - } - const cppbor::Bstr* encodedDE = (taggedEncodedDE->child())->asBstr(); - if (encodedDE == nullptr) { - return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( - IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND, - "Child of semantic in first item in SessionTranscript " - "array is not a bstr")); - } - const vector& bytesDE = encodedDE->value(); - auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_); if (!getXYSuccess) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( @@ -370,8 +357,10 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval( "Error extracting X and Y from ePub")); } if (sessionTranscript.size() > 0 && - !(memmem(bytesDE.data(), bytesDE.size(), ePubX.data(), ePubX.size()) != nullptr && - memmem(bytesDE.data(), bytesDE.size(), ePubY.data(), ePubY.size()) != nullptr)) { + !(memmem(sessionTranscript.data(), sessionTranscript.size(), ePubX.data(), + ePubX.size()) != nullptr && + memmem(sessionTranscript.data(), sessionTranscript.size(), ePubY.data(), + ePubY.size()) != nullptr)) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND, "Did not find ephemeral public key's X and Y coordinates in " @@ -478,9 +467,10 @@ ndk::ScopedAStatus IdentityCredential::startRetrieval( } // Validate all the access control profiles in the requestData. - bool haveAuthToken = (authToken.mac.size() > 0); + bool haveAuthToken = (authToken.timestamp.milliSeconds != int64_t(0)); for (const auto& profile : accessControlProfiles) { if (!secureAccessControlProfileCheckMac(profile, storageKey_)) { + LOG(ERROR) << "Error checking MAC for profile"; return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_INVALID_DATA, "Error checking MAC for profile")); @@ -796,7 +786,7 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector* outMac, array.add(sessionTranscriptItem_->clone()); array.add(docType_); array.add(cppbor::Semantic(24, encodedDeviceNameSpaces)); - vector encodedDeviceAuthentication = array.encode(); + vector deviceAuthenticationBytes = cppbor::Semantic(24, array.encode()).encode(); vector docTypeAsBlob(docType_.begin(), docType_.end()); optional> signingKey = @@ -814,17 +804,24 @@ ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector* outMac, IIdentityCredentialStore::STATUS_FAILED, "Error doing ECDH")); } + // Mix-in SessionTranscriptBytes + vector sessionTranscriptBytes = cppbor::Semantic(24, sessionTranscript_).encode(); + vector sharedSecretWithSessionTranscriptBytes = sharedSecret.value(); + std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(), + std::back_inserter(sharedSecretWithSessionTranscriptBytes)); + vector salt = {0x00}; vector info = {}; - optional> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32); + optional> derivedKey = + support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32); if (!derivedKey) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error deriving key from shared secret")); } - mac = support::coseMac0(derivedKey.value(), {}, // payload - encodedDeviceAuthentication); // additionalData + mac = support::coseMac0(derivedKey.value(), {}, // payload + deviceAuthenticationBytes); // detached content if (!mac) { return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( IIdentityCredentialStore::STATUS_FAILED, "Error MACing data")); diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp index 7732c33a16..c218866ace 100644 --- a/identity/aidl/default/WritableIdentityCredential.cpp +++ b/identity/aidl/default/WritableIdentityCredential.cpp @@ -65,6 +65,10 @@ ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate( IIdentityCredentialStore::STATUS_FAILED, "Error attestation certificate previously generated")); } + if (attestationChallenge.empty()) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_INVALID_DATA, "Challenge can not be empty")); + } vector challenge(attestationChallenge.begin(), attestationChallenge.end()); vector appId(attestationApplicationId.begin(), attestationApplicationId.end()); @@ -165,6 +169,13 @@ ndk::ScopedAStatus WritableIdentityCredential::addAccessControlProfile( "userAuthenticationRequired is false but timeout is non-zero")); } + // If |userAuthenticationRequired| is true, then |secureUserId| must be non-zero. + if (userAuthenticationRequired && secureUserId == 0) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IIdentityCredentialStore::STATUS_INVALID_DATA, + "userAuthenticationRequired is true but secureUserId is zero")); + } + profile.id = id; profile.readerCertificate = readerCertificate; profile.userAuthenticationRequired = userAuthenticationRequired; diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp index 5b075c6e67..c1f44e742e 100644 --- a/identity/aidl/vts/Android.bp +++ b/identity/aidl/vts/Android.bp @@ -10,20 +10,23 @@ cc_test { "VtsIdentityTestUtils.cpp", "VtsAttestationTests.cpp", "VtsAttestationParserSupport.cpp", + "UserAuthTests.cpp", + "ReaderAuthTests.cpp", ], shared_libs: [ - "android.hardware.keymaster@4.0", "libbinder", "libcrypto", - "libkeymaster_portable", - "libsoft_attestation_cert", - "libpuresoftkeymasterdevice", ], static_libs: [ "libcppbor", + "libkeymaster_portable", + "libsoft_attestation_cert", + "libpuresoftkeymasterdevice", + "android.hardware.keymaster@4.0", "android.hardware.identity-support-lib", "android.hardware.identity-cpp", "android.hardware.keymaster-cpp", + "android.hardware.keymaster-ndk_platform", ], test_suites: [ "general-tests", diff --git a/identity/aidl/vts/ReaderAuthTests.cpp b/identity/aidl/vts/ReaderAuthTests.cpp new file mode 100644 index 0000000000..b11f6c5e8f --- /dev/null +++ b/identity/aidl/vts/ReaderAuthTests.cpp @@ -0,0 +1,602 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "ReaderAuthTests" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "VtsIdentityTestUtils.h" + +namespace android::hardware::identity { + +using std::endl; +using std::make_pair; +using std::map; +using std::optional; +using std::pair; +using std::string; +using std::tie; +using std::vector; + +using ::android::sp; +using ::android::String16; +using ::android::binder::Status; + +using ::android::hardware::keymaster::HardwareAuthToken; +using ::android::hardware::keymaster::VerificationToken; + +class ReaderAuthTests : public testing::TestWithParam { + public: + virtual void SetUp() override { + credentialStore_ = android::waitForDeclaredService( + String16(GetParam().c_str())); + ASSERT_NE(credentialStore_, nullptr); + } + + void provisionData(); + void retrieveData(const vector& readerPrivateKey, + const vector>& readerCertChain, bool expectSuccess, + bool leaveOutAccessibleToAllFromRequestMessage); + + // Set by provisionData + vector readerPublicKey_; + vector readerPrivateKey_; + vector intermediateAPublicKey_; + vector intermediateAPrivateKey_; + vector intermediateBPublicKey_; + vector intermediateBPrivateKey_; + vector intermediateCPublicKey_; + vector intermediateCPrivateKey_; + + vector cert_A_SelfSigned_; + + vector cert_B_SelfSigned_; + + vector cert_B_SignedBy_C_; + + vector cert_C_SelfSigned_; + + vector cert_reader_SelfSigned_; + vector cert_reader_SignedBy_A_; + vector cert_reader_SignedBy_B_; + + SecureAccessControlProfile sacp0_; + SecureAccessControlProfile sacp1_; + SecureAccessControlProfile sacp2_; + SecureAccessControlProfile sacp3_; + + vector encContentAccessibleByA_; + vector encContentAccessibleByAorB_; + vector encContentAccessibleByB_; + vector encContentAccessibleByC_; + vector encContentAccessibleByAll_; + vector encContentAccessibleByNone_; + + vector credentialData_; + + // Set by retrieveData() + bool canGetAccessibleByA_; + bool canGetAccessibleByAorB_; + bool canGetAccessibleByB_; + bool canGetAccessibleByC_; + bool canGetAccessibleByAll_; + bool canGetAccessibleByNone_; + + sp credentialStore_; +}; + +pair, vector> generateReaderKey() { + optional> keyPKCS8 = support::createEcKeyPair(); + optional> publicKey = support::ecKeyPairGetPublicKey(keyPKCS8.value()); + optional> privateKey = support::ecKeyPairGetPrivateKey(keyPKCS8.value()); + return make_pair(publicKey.value(), privateKey.value()); +} + +vector generateReaderCert(const vector& publicKey, + const vector& signingKey) { + time_t validityNotBefore = 0; + time_t validityNotAfter = 0xffffffff; + optional> cert = + support::ecPublicKeyGenerateCertificate(publicKey, signingKey, "24601", "Issuer", + "Subject", validityNotBefore, validityNotAfter); + return cert.value(); +} + +void ReaderAuthTests::provisionData() { + // Keys and certificates for intermediates. + tie(intermediateAPublicKey_, intermediateAPrivateKey_) = generateReaderKey(); + tie(intermediateBPublicKey_, intermediateBPrivateKey_) = generateReaderKey(); + tie(intermediateCPublicKey_, intermediateCPrivateKey_) = generateReaderKey(); + + cert_A_SelfSigned_ = generateReaderCert(intermediateAPublicKey_, intermediateAPrivateKey_); + + cert_B_SelfSigned_ = generateReaderCert(intermediateBPublicKey_, intermediateBPrivateKey_); + + cert_B_SignedBy_C_ = generateReaderCert(intermediateBPublicKey_, intermediateCPrivateKey_); + + cert_C_SelfSigned_ = generateReaderCert(intermediateCPublicKey_, intermediateCPrivateKey_); + + // Key and self-signed certificate reader + tie(readerPublicKey_, readerPrivateKey_) = generateReaderKey(); + cert_reader_SelfSigned_ = generateReaderCert(readerPublicKey_, readerPrivateKey_); + + // Certificate for reader signed by intermediates + cert_reader_SignedBy_A_ = generateReaderCert(readerPublicKey_, intermediateAPrivateKey_); + cert_reader_SignedBy_B_ = generateReaderCert(readerPublicKey_, intermediateBPrivateKey_); + + string docType = "org.iso.18013-5.2019.mdl"; + bool testCredential = true; + sp wc; + ASSERT_TRUE(credentialStore_->createCredential(docType, testCredential, &wc).isOk()); + + vector attestationApplicationId = {}; + vector attestationChallenge = {1}; + vector certChain; + ASSERT_TRUE(wc->getAttestationCertificate(attestationApplicationId, attestationChallenge, + &certChain) + .isOk()); + + size_t proofOfProvisioningSize = + 465 + cert_A_SelfSigned_.size() + cert_B_SelfSigned_.size() + cert_C_SelfSigned_.size(); + ASSERT_TRUE(wc->setExpectedProofOfProvisioningSize(proofOfProvisioningSize).isOk()); + + // Not in v1 HAL, may fail + wc->startPersonalization(4 /* numAccessControlProfiles */, + {6} /* numDataElementsPerNamespace */); + + // AIDL expects certificates wrapped in the Certificate type... + Certificate cert_A; + Certificate cert_B; + Certificate cert_C; + cert_A.encodedCertificate = cert_A_SelfSigned_; + cert_B.encodedCertificate = cert_B_SelfSigned_; + cert_C.encodedCertificate = cert_C_SelfSigned_; + + // Access control profile 0: accessible by A + ASSERT_TRUE(wc->addAccessControlProfile(0, cert_A, false, 0, 0, &sacp0_).isOk()); + + // Access control profile 1: accessible by B + ASSERT_TRUE(wc->addAccessControlProfile(1, cert_B, false, 0, 0, &sacp1_).isOk()); + + // Access control profile 2: accessible by C + ASSERT_TRUE(wc->addAccessControlProfile(2, cert_C, false, 0, 0, &sacp2_).isOk()); + + // Access control profile 3: open access + ASSERT_TRUE(wc->addAccessControlProfile(3, {}, false, 0, 0, &sacp3_).isOk()); + + // Data Element: "Accessible by A" + ASSERT_TRUE(wc->beginAddEntry({0}, "ns", "Accessible by A", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByA_).isOk()); + + // Data Element: "Accessible by A or B" + ASSERT_TRUE(wc->beginAddEntry({0, 1}, "ns", "Accessible by A or B", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByAorB_).isOk()); + + // Data Element: "Accessible by B" + ASSERT_TRUE(wc->beginAddEntry({1}, "ns", "Accessible by B", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByB_).isOk()); + + // Data Element: "Accessible by C" + ASSERT_TRUE(wc->beginAddEntry({2}, "ns", "Accessible by C", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByC_).isOk()); + + // Data Element: "Accessible by All" + ASSERT_TRUE(wc->beginAddEntry({3}, "ns", "Accessible by All", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByAll_).isOk()); + + // Data Element: "Accessible by None" + ASSERT_TRUE(wc->beginAddEntry({}, "ns", "Accessible by None", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByNone_).isOk()); + + vector proofOfProvisioningSignature; + ASSERT_TRUE(wc->finishAddingEntries(&credentialData_, &proofOfProvisioningSignature).isOk()); +} + +RequestDataItem buildRequestDataItem(const string& name, size_t size, + vector accessControlProfileIds) { + RequestDataItem item; + item.name = name; + item.size = size; + item.accessControlProfileIds = accessControlProfileIds; + return item; +} + +void ReaderAuthTests::retrieveData(const vector& readerPrivateKey, + const vector>& readerCertChain, + bool expectSuccess, + bool leaveOutAccessibleToAllFromRequestMessage) { + canGetAccessibleByA_ = false; + canGetAccessibleByAorB_ = false; + canGetAccessibleByB_ = false; + canGetAccessibleByC_ = false; + canGetAccessibleByAll_ = false; + canGetAccessibleByNone_ = false; + + sp c; + ASSERT_TRUE(credentialStore_ + ->getCredential( + CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256, + credentialData_, &c) + .isOk()); + + optional> readerEKeyPair = support::createEcKeyPair(); + optional> readerEPublicKey = + support::ecKeyPairGetPublicKey(readerEKeyPair.value()); + ASSERT_TRUE(c->setReaderEphemeralPublicKey(readerEPublicKey.value()).isOk()); + + vector eKeyPair; + ASSERT_TRUE(c->createEphemeralKeyPair(&eKeyPair).isOk()); + optional> ePublicKey = support::ecKeyPairGetPublicKey(eKeyPair); + + // Calculate requestData field and sign it with the reader key. + auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ePublicKey.value()); + ASSERT_TRUE(getXYSuccess); + cppbor::Map deviceEngagement = cppbor::Map().add("ephX", ephX).add("ephY", ephY); + vector deviceEngagementBytes = deviceEngagement.encode(); + vector eReaderPubBytes = cppbor::Tstr("ignored").encode(); + cppbor::Array sessionTranscript = cppbor::Array() + .add(cppbor::Semantic(24, deviceEngagementBytes)) + .add(cppbor::Semantic(24, eReaderPubBytes)); + vector sessionTranscriptBytes = sessionTranscript.encode(); + + vector itemsRequestBytes; + if (leaveOutAccessibleToAllFromRequestMessage) { + itemsRequestBytes = + cppbor::Map("nameSpaces", + cppbor::Map().add("ns", cppbor::Map() + .add("Accessible by A", false) + .add("Accessible by A or B", false) + .add("Accessible by B", false) + .add("Accessible by C", false) + .add("Accessible by None", false))) + .encode(); + } else { + itemsRequestBytes = + cppbor::Map("nameSpaces", + cppbor::Map().add("ns", cppbor::Map() + .add("Accessible by A", false) + .add("Accessible by A or B", false) + .add("Accessible by B", false) + .add("Accessible by C", false) + .add("Accessible by All", false) + .add("Accessible by None", false))) + .encode(); + } + vector encodedReaderAuthentication = + cppbor::Array() + .add("ReaderAuthentication") + .add(sessionTranscript.clone()) + .add(cppbor::Semantic(24, itemsRequestBytes)) + .encode(); + vector encodedReaderAuthenticationBytes = + cppbor::Semantic(24, encodedReaderAuthentication).encode(); + + optional> readerSignature = + support::coseSignEcDsa(readerPrivateKey, // private key for reader + {}, // content + encodedReaderAuthenticationBytes, // detached content + support::certificateChainJoin(readerCertChain)); + ASSERT_TRUE(readerSignature); + + // Generate the key that will be used to sign AuthenticatedData. + vector signingKeyBlob; + Certificate signingKeyCertificate; + ASSERT_TRUE(c->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk()); + + RequestNamespace rns; + rns.namespaceName = "ns"; + rns.items.push_back(buildRequestDataItem("Accessible by A", 1, {0})); + rns.items.push_back(buildRequestDataItem("Accessible by A or B", 1, {0, 1})); + rns.items.push_back(buildRequestDataItem("Accessible by B", 1, {1})); + rns.items.push_back(buildRequestDataItem("Accessible by C", 1, {2})); + rns.items.push_back(buildRequestDataItem("Accessible by All", 1, {3})); + rns.items.push_back(buildRequestDataItem("Accessible by None", 1, {})); + // OK to fail, not available in v1 HAL + c->setRequestedNamespaces({rns}).isOk(); + + // It doesn't matter since no user auth is needed in this particular test, + // but for good measure, clear out the tokens we pass to the HAL. + HardwareAuthToken authToken; + VerificationToken verificationToken; + authToken.challenge = 0; + authToken.userId = 0; + authToken.authenticatorId = 0; + authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE; + authToken.timestamp.milliSeconds = 0; + authToken.mac.clear(); + verificationToken.challenge = 0; + verificationToken.timestamp.milliSeconds = 0; + verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE; + verificationToken.mac.clear(); + // OK to fail, not available in v1 HAL + c->setVerificationToken(verificationToken); + + Status status = c->startRetrieval( + {sacp0_, sacp1_, sacp2_, sacp3_}, authToken, itemsRequestBytes, signingKeyBlob, + sessionTranscriptBytes, readerSignature.value(), {6 /* numDataElementsPerNamespace */}); + if (expectSuccess) { + ASSERT_TRUE(status.isOk()); + } else { + ASSERT_FALSE(status.isOk()); + return; + } + + vector decrypted; + + status = c->startRetrieveEntryValue("ns", "Accessible by A", 1, {0}); + if (status.isOk()) { + canGetAccessibleByA_ = true; + ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByA_, &decrypted).isOk()); + } + + status = c->startRetrieveEntryValue("ns", "Accessible by A or B", 1, {0, 1}); + if (status.isOk()) { + canGetAccessibleByAorB_ = true; + ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByAorB_, &decrypted).isOk()); + } + + status = c->startRetrieveEntryValue("ns", "Accessible by B", 1, {1}); + if (status.isOk()) { + canGetAccessibleByB_ = true; + ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByB_, &decrypted).isOk()); + } + + status = c->startRetrieveEntryValue("ns", "Accessible by C", 1, {2}); + if (status.isOk()) { + canGetAccessibleByC_ = true; + ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByC_, &decrypted).isOk()); + } + + status = c->startRetrieveEntryValue("ns", "Accessible by All", 1, {3}); + if (status.isOk()) { + canGetAccessibleByAll_ = true; + ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByAll_, &decrypted).isOk()); + } + + status = c->startRetrieveEntryValue("ns", "Accessible by None", 1, {}); + if (status.isOk()) { + canGetAccessibleByNone_ = true; + ASSERT_TRUE(c->retrieveEntryValue(encContentAccessibleByNone_, &decrypted).isOk()); + } + + vector mac; + vector deviceNameSpaces; + ASSERT_TRUE(c->finishRetrieval(&mac, &deviceNameSpaces).isOk()); +} + +TEST_P(ReaderAuthTests, presentingChain_Reader) { + provisionData(); + retrieveData(readerPrivateKey_, {cert_reader_SelfSigned_}, true /* expectSuccess */, + false /* leaveOutAccessibleToAllFromRequestMessage */); + EXPECT_FALSE(canGetAccessibleByA_); + EXPECT_FALSE(canGetAccessibleByAorB_); + EXPECT_FALSE(canGetAccessibleByB_); + EXPECT_FALSE(canGetAccessibleByC_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +TEST_P(ReaderAuthTests, presentingChain_Reader_A) { + provisionData(); + retrieveData(readerPrivateKey_, {cert_reader_SignedBy_A_, cert_A_SelfSigned_}, + true /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */); + EXPECT_TRUE(canGetAccessibleByA_); + EXPECT_TRUE(canGetAccessibleByAorB_); + EXPECT_FALSE(canGetAccessibleByB_); + EXPECT_FALSE(canGetAccessibleByC_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +TEST_P(ReaderAuthTests, presentingChain_Reader_B) { + provisionData(); + retrieveData(readerPrivateKey_, {cert_reader_SignedBy_B_, cert_B_SelfSigned_}, + true /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */); + EXPECT_FALSE(canGetAccessibleByA_); + EXPECT_TRUE(canGetAccessibleByAorB_); + EXPECT_TRUE(canGetAccessibleByB_); + EXPECT_FALSE(canGetAccessibleByC_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +// This test proves that for the purpose of determining inclusion of an ACP certificate +// in a presented reader chain, certificate equality is done by comparing public keys, +// not bitwise comparison of the certificates. +// +// Specifically for this test, the ACP is configured with cert_B_SelfSigned_ and the +// reader is presenting cert_B_SignedBy_C_. Both certificates have the same public +// key - intermediateBPublicKey_ - but they are signed by different keys. +// +TEST_P(ReaderAuthTests, presentingChain_Reader_B_C) { + provisionData(); + retrieveData(readerPrivateKey_, + {cert_reader_SignedBy_B_, cert_B_SignedBy_C_, cert_C_SelfSigned_}, + true /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */); + EXPECT_FALSE(canGetAccessibleByA_); + EXPECT_TRUE(canGetAccessibleByAorB_); + EXPECT_TRUE(canGetAccessibleByB_); + EXPECT_TRUE(canGetAccessibleByC_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +// This test presents a reader chain where the chain is invalid because +// the 2nd certificate in the chain isn't signed by the 3rd one. +// +TEST_P(ReaderAuthTests, presentingInvalidChain) { + provisionData(); + retrieveData(readerPrivateKey_, + {cert_reader_SignedBy_B_, cert_B_SelfSigned_, cert_C_SelfSigned_}, + false /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */); +} + +// This tests presents a valid reader chain but where requestMessage isn't +// signed by the private key corresponding to the public key in the top-level +// certificate. +// +TEST_P(ReaderAuthTests, presentingMessageSignedNotByTopLevel) { + provisionData(); + retrieveData(intermediateBPrivateKey_, + {cert_reader_SignedBy_B_, cert_B_SignedBy_C_, cert_C_SelfSigned_}, + false /* expectSuccess */, false /* leaveOutAccessibleToAllFromRequestMessage */); +} + +// This test leaves out "Accessible by All" data element from the signed request +// message (the CBOR from the reader) while still including this data element at +// the API level. The call on the API level for said element will fail with +// STATUS_NOT_IN_REQUEST_MESSAGE but this doesn't prevent the other elements +// from being returned (if authorized, of course). +// +// This test verifies that. +// +TEST_P(ReaderAuthTests, limitedMessage) { + provisionData(); + retrieveData(readerPrivateKey_, {cert_reader_SelfSigned_}, true /* expectSuccess */, + true /* leaveOutAccessibleToAllFromRequestMessage */); + EXPECT_FALSE(canGetAccessibleByA_); + EXPECT_FALSE(canGetAccessibleByAorB_); + EXPECT_FALSE(canGetAccessibleByB_); + EXPECT_FALSE(canGetAccessibleByC_); + EXPECT_FALSE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +TEST_P(ReaderAuthTests, ephemeralKeyNotInSessionTranscript) { + provisionData(); + + sp c; + ASSERT_TRUE(credentialStore_ + ->getCredential( + CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256, + credentialData_, &c) + .isOk()); + + optional> readerEKeyPair = support::createEcKeyPair(); + optional> readerEPublicKey = + support::ecKeyPairGetPublicKey(readerEKeyPair.value()); + ASSERT_TRUE(c->setReaderEphemeralPublicKey(readerEPublicKey.value()).isOk()); + + vector eKeyPair; + ASSERT_TRUE(c->createEphemeralKeyPair(&eKeyPair).isOk()); + optional> ePublicKey = support::ecKeyPairGetPublicKey(eKeyPair); + + // Calculate requestData field and sign it with the reader key. + auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ePublicKey.value()); + ASSERT_TRUE(getXYSuccess); + // Instead of include the X and Y coordinates (|ephX| and |ephY|), add NUL bytes instead. + vector nulls(32); + cppbor::Map deviceEngagement = cppbor::Map().add("ephX", nulls).add("ephY", nulls); + vector deviceEngagementBytes = deviceEngagement.encode(); + vector eReaderPubBytes = cppbor::Tstr("ignored").encode(); + cppbor::Array sessionTranscript = cppbor::Array() + .add(cppbor::Semantic(24, deviceEngagementBytes)) + .add(cppbor::Semantic(24, eReaderPubBytes)); + vector sessionTranscriptBytes = sessionTranscript.encode(); + + vector itemsRequestBytes; + itemsRequestBytes = + cppbor::Map("nameSpaces", + cppbor::Map().add("ns", cppbor::Map() + .add("Accessible by A", false) + .add("Accessible by A or B", false) + .add("Accessible by B", false) + .add("Accessible by C", false) + .add("Accessible by None", false))) + .encode(); + vector encodedReaderAuthentication = + cppbor::Array() + .add("ReaderAuthentication") + .add(sessionTranscript.clone()) + .add(cppbor::Semantic(24, itemsRequestBytes)) + .encode(); + vector encodedReaderAuthenticationBytes = + cppbor::Semantic(24, encodedReaderAuthentication).encode(); + + vector> readerCertChain = {cert_reader_SelfSigned_}; + optional> readerSignature = + support::coseSignEcDsa(readerPrivateKey_, // private key for reader + {}, // content + encodedReaderAuthenticationBytes, // detached content + support::certificateChainJoin(readerCertChain)); + ASSERT_TRUE(readerSignature); + + // Generate the key that will be used to sign AuthenticatedData. + vector signingKeyBlob; + Certificate signingKeyCertificate; + ASSERT_TRUE(c->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk()); + + RequestNamespace rns; + rns.namespaceName = "ns"; + rns.items.push_back(buildRequestDataItem("Accessible by A", 1, {0})); + rns.items.push_back(buildRequestDataItem("Accessible by A or B", 1, {0, 1})); + rns.items.push_back(buildRequestDataItem("Accessible by B", 1, {1})); + rns.items.push_back(buildRequestDataItem("Accessible by C", 1, {2})); + rns.items.push_back(buildRequestDataItem("Accessible by All", 1, {3})); + rns.items.push_back(buildRequestDataItem("Accessible by None", 1, {})); + // OK to fail, not available in v1 HAL + c->setRequestedNamespaces({rns}).isOk(); + + // It doesn't matter since no user auth is needed in this particular test, + // but for good measure, clear out the tokens we pass to the HAL. + HardwareAuthToken authToken; + VerificationToken verificationToken; + authToken.challenge = 0; + authToken.userId = 0; + authToken.authenticatorId = 0; + authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE; + authToken.timestamp.milliSeconds = 0; + authToken.mac.clear(); + verificationToken.challenge = 0; + verificationToken.timestamp.milliSeconds = 0; + verificationToken.securityLevel = + ::android::hardware::keymaster::SecurityLevel::TRUSTED_ENVIRONMENT; + verificationToken.mac.clear(); + // OK to fail, not available in v1 HAL + c->setVerificationToken(verificationToken); + + // Finally check that STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND is returned. + // This proves that the TA checked for X and Y coordinatets and didn't find + // them. + Status status = c->startRetrieval( + {sacp0_, sacp1_, sacp2_, sacp3_}, authToken, itemsRequestBytes, signingKeyBlob, + sessionTranscriptBytes, readerSignature.value(), {6 /* numDataElementsPerNamespace */}); + ASSERT_FALSE(status.isOk()); + ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode()); + ASSERT_EQ(IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND, + status.serviceSpecificErrorCode()); +} + +INSTANTIATE_TEST_SUITE_P( + Identity, ReaderAuthTests, + testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)), + android::PrintInstanceNameToString); + +} // namespace android::hardware::identity diff --git a/identity/aidl/vts/UserAuthTests.cpp b/identity/aidl/vts/UserAuthTests.cpp new file mode 100644 index 0000000000..5b4c8f12ef --- /dev/null +++ b/identity/aidl/vts/UserAuthTests.cpp @@ -0,0 +1,473 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "UserAuthTests" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "VtsIdentityTestUtils.h" + +namespace android::hardware::identity { + +using std::endl; +using std::make_pair; +using std::map; +using std::optional; +using std::pair; +using std::string; +using std::tie; +using std::vector; + +using ::android::sp; +using ::android::String16; +using ::android::binder::Status; + +using ::android::hardware::keymaster::HardwareAuthToken; +using ::android::hardware::keymaster::VerificationToken; + +class UserAuthTests : public testing::TestWithParam { + public: + virtual void SetUp() override { + credentialStore_ = android::waitForDeclaredService( + String16(GetParam().c_str())); + ASSERT_NE(credentialStore_, nullptr); + } + + void provisionData(); + void setupRetrieveData(); + pair mintTokens(uint64_t challengeForAuthToken, + int64_t ageOfAuthTokenMilliSeconds); + void retrieveData(HardwareAuthToken authToken, VerificationToken verificationToken, + bool expectSuccess, bool useSessionTranscript); + + // Set by provisionData + SecureAccessControlProfile sacp0_; + SecureAccessControlProfile sacp1_; + SecureAccessControlProfile sacp2_; + + vector encContentUserAuthPerSession_; + vector encContentUserAuthTimeout_; + vector encContentAccessibleByAll_; + vector encContentAccessibleByNone_; + + vector credentialData_; + + // Set by setupRetrieveData(). + int64_t authChallenge_; + cppbor::Map sessionTranscript_; + sp credential_; + + // Set by retrieveData() + bool canGetUserAuthPerSession_; + bool canGetUserAuthTimeout_; + bool canGetAccessibleByAll_; + bool canGetAccessibleByNone_; + + sp credentialStore_; +}; + +void UserAuthTests::provisionData() { + string docType = "org.iso.18013-5.2019.mdl"; + bool testCredential = true; + sp wc; + ASSERT_TRUE(credentialStore_->createCredential(docType, testCredential, &wc).isOk()); + + vector attestationApplicationId = {}; + vector attestationChallenge = {1}; + vector certChain; + ASSERT_TRUE(wc->getAttestationCertificate(attestationApplicationId, attestationChallenge, + &certChain) + .isOk()); + + size_t proofOfProvisioningSize = 381; + // Not in v1 HAL, may fail + wc->setExpectedProofOfProvisioningSize(proofOfProvisioningSize); + + ASSERT_TRUE(wc->startPersonalization(3 /* numAccessControlProfiles */, + {4} /* numDataElementsPerNamespace */) + .isOk()); + + // Access control profile 0: user auth every session (timeout = 0) + ASSERT_TRUE(wc->addAccessControlProfile(0, {}, true, 0, 65 /* secureUserId */, &sacp0_).isOk()); + + // Access control profile 1: user auth, 60 seconds timeout + ASSERT_TRUE( + wc->addAccessControlProfile(1, {}, true, 60000, 65 /* secureUserId */, &sacp1_).isOk()); + + // Access control profile 2: open access + ASSERT_TRUE(wc->addAccessControlProfile(2, {}, false, 0, 0, &sacp2_).isOk()); + + // Data Element: "UserAuth Per Session" + ASSERT_TRUE(wc->beginAddEntry({0}, "ns", "UserAuth Per Session", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentUserAuthPerSession_).isOk()); + + // Data Element: "UserAuth Timeout" + ASSERT_TRUE(wc->beginAddEntry({1}, "ns", "UserAuth Timeout", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentUserAuthTimeout_).isOk()); + + // Data Element: "Accessible by All" + ASSERT_TRUE(wc->beginAddEntry({2}, "ns", "Accessible by All", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByAll_).isOk()); + + // Data Element: "Accessible by None" + ASSERT_TRUE(wc->beginAddEntry({}, "ns", "Accessible by None", 1).isOk()); + ASSERT_TRUE(wc->addEntryValue({9}, &encContentAccessibleByNone_).isOk()); + + vector proofOfProvisioningSignature; + Status status = wc->finishAddingEntries(&credentialData_, &proofOfProvisioningSignature); + EXPECT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage(); +} + +// From ReaderAuthTest.cpp - TODO: consolidate with VtsIdentityTestUtils.h +pair, vector> generateReaderKey(); +vector generateReaderCert(const vector& publicKey, + const vector& signingKey); +RequestDataItem buildRequestDataItem(const string& name, size_t size, + vector accessControlProfileIds); + +cppbor::Map calcSessionTranscript(const vector& ePublicKey) { + auto [getXYSuccess, ephX, ephY] = support::ecPublicKeyGetXandY(ePublicKey); + cppbor::Map deviceEngagement = cppbor::Map().add("ephX", ephX).add("ephY", ephY); + vector deviceEngagementBytes = deviceEngagement.encode(); + vector eReaderPubBytes = cppbor::Tstr("ignored").encode(); + // Let SessionTranscript be a map here (it's an array in EndToEndTest) just + // to check that the implementation can deal with either. + cppbor::Map sessionTranscript; + sessionTranscript.add(42, cppbor::Semantic(24, deviceEngagementBytes)); + sessionTranscript.add(43, cppbor::Semantic(24, eReaderPubBytes)); + return sessionTranscript; +} + +void UserAuthTests::setupRetrieveData() { + ASSERT_TRUE(credentialStore_ + ->getCredential( + CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256, + credentialData_, &credential_) + .isOk()); + + optional> readerEKeyPair = support::createEcKeyPair(); + optional> readerEPublicKey = + support::ecKeyPairGetPublicKey(readerEKeyPair.value()); + ASSERT_TRUE(credential_->setReaderEphemeralPublicKey(readerEPublicKey.value()).isOk()); + + vector eKeyPair; + ASSERT_TRUE(credential_->createEphemeralKeyPair(&eKeyPair).isOk()); + optional> ePublicKey = support::ecKeyPairGetPublicKey(eKeyPair); + sessionTranscript_ = calcSessionTranscript(ePublicKey.value()); + + Status status = credential_->createAuthChallenge(&authChallenge_); + EXPECT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage(); +} + +void UserAuthTests::retrieveData(HardwareAuthToken authToken, VerificationToken verificationToken, + bool expectSuccess, bool useSessionTranscript) { + canGetUserAuthPerSession_ = false; + canGetUserAuthTimeout_ = false; + canGetAccessibleByAll_ = false; + canGetAccessibleByNone_ = false; + + vector itemsRequestBytes; + vector sessionTranscriptBytes; + if (useSessionTranscript) { + sessionTranscriptBytes = sessionTranscript_.encode(); + + itemsRequestBytes = + cppbor::Map("nameSpaces", + cppbor::Map().add("ns", cppbor::Map() + .add("UserAuth Per Session", false) + .add("UserAuth Timeout", false) + .add("Accessible by All", false) + .add("Accessible by None", false))) + .encode(); + vector dataToSign = cppbor::Array() + .add("ReaderAuthentication") + .add(sessionTranscript_.clone()) + .add(cppbor::Semantic(24, itemsRequestBytes)) + .encode(); + } + + // Generate the key that will be used to sign AuthenticatedData. + vector signingKeyBlob; + Certificate signingKeyCertificate; + ASSERT_TRUE( + credential_->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk()); + + RequestNamespace rns; + rns.namespaceName = "ns"; + rns.items.push_back(buildRequestDataItem("UserAuth Per Session", 1, {0})); + rns.items.push_back(buildRequestDataItem("UserAuth Timeout", 1, {1})); + rns.items.push_back(buildRequestDataItem("Accessible by All", 1, {2})); + rns.items.push_back(buildRequestDataItem("Accessible by None", 1, {})); + // OK to fail, not available in v1 HAL + credential_->setRequestedNamespaces({rns}).isOk(); + + // OK to fail, not available in v1 HAL + credential_->setVerificationToken(verificationToken); + + Status status = credential_->startRetrieval({sacp0_, sacp1_, sacp2_}, authToken, + itemsRequestBytes, signingKeyBlob, + sessionTranscriptBytes, {} /* readerSignature */, + {4 /* numDataElementsPerNamespace */}); + if (expectSuccess) { + ASSERT_TRUE(status.isOk()); + } else { + ASSERT_FALSE(status.isOk()); + return; + } + + vector decrypted; + + status = credential_->startRetrieveEntryValue("ns", "UserAuth Per Session", 1, {0}); + if (status.isOk()) { + canGetUserAuthPerSession_ = true; + ASSERT_TRUE( + credential_->retrieveEntryValue(encContentUserAuthPerSession_, &decrypted).isOk()); + } + + status = credential_->startRetrieveEntryValue("ns", "UserAuth Timeout", 1, {1}); + if (status.isOk()) { + canGetUserAuthTimeout_ = true; + ASSERT_TRUE(credential_->retrieveEntryValue(encContentUserAuthTimeout_, &decrypted).isOk()); + } + + status = credential_->startRetrieveEntryValue("ns", "Accessible by All", 1, {2}); + if (status.isOk()) { + canGetAccessibleByAll_ = true; + ASSERT_TRUE(credential_->retrieveEntryValue(encContentAccessibleByAll_, &decrypted).isOk()); + } + + status = credential_->startRetrieveEntryValue("ns", "Accessible by None", 1, {}); + if (status.isOk()) { + canGetAccessibleByNone_ = true; + ASSERT_TRUE( + credential_->retrieveEntryValue(encContentAccessibleByNone_, &decrypted).isOk()); + } + + vector mac; + vector deviceNameSpaces; + ASSERT_TRUE(credential_->finishRetrieval(&mac, &deviceNameSpaces).isOk()); +} + +pair UserAuthTests::mintTokens( + uint64_t challengeForAuthToken, int64_t ageOfAuthTokenMilliSeconds) { + HardwareAuthToken authToken; + VerificationToken verificationToken; + + uint64_t epochMilliseconds = 1000ULL * 1000ULL * 1000ULL * 1000ULL; + + authToken.challenge = challengeForAuthToken; + authToken.userId = 65; + authToken.authenticatorId = 0; + authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE; + authToken.timestamp.milliSeconds = epochMilliseconds - ageOfAuthTokenMilliSeconds; + authToken.mac.clear(); + verificationToken.challenge = authChallenge_; + verificationToken.timestamp.milliSeconds = epochMilliseconds; + verificationToken.securityLevel = + ::android::hardware::keymaster::SecurityLevel::TRUSTED_ENVIRONMENT; + verificationToken.mac.clear(); + return make_pair(authToken, verificationToken); +} + +TEST_P(UserAuthTests, GoodChallenge) { + provisionData(); + setupRetrieveData(); + auto [authToken, verificationToken] = mintTokens(authChallenge_, // challengeForAuthToken + 0); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_TRUE(canGetUserAuthPerSession_); + EXPECT_TRUE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +TEST_P(UserAuthTests, OtherChallenge) { + provisionData(); + setupRetrieveData(); + uint64_t otherChallenge = authChallenge_ ^ 0x12345678; + auto [authToken, verificationToken] = mintTokens(otherChallenge, // challengeForAuthToken + 0); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_TRUE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +TEST_P(UserAuthTests, NoChallenge) { + provisionData(); + setupRetrieveData(); + auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken + 0); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_TRUE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +TEST_P(UserAuthTests, AuthTokenAgeZero) { + provisionData(); + setupRetrieveData(); + auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken + 0); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_TRUE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +TEST_P(UserAuthTests, AuthTokenFromTheFuture) { + provisionData(); + setupRetrieveData(); + auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken + -1 * 1000); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_FALSE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +TEST_P(UserAuthTests, AuthTokenInsideTimeout) { + provisionData(); + setupRetrieveData(); + auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken + 30 * 1000); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_TRUE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +TEST_P(UserAuthTests, AuthTokenOutsideTimeout) { + provisionData(); + setupRetrieveData(); + auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken + 61 * 1000); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_FALSE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +// The API works even when there's no SessionTranscript / itemsRequest. +// Verify that. +TEST_P(UserAuthTests, NoSessionTranscript) { + provisionData(); + setupRetrieveData(); + auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken + 1 * 1000); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + false /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_TRUE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +// This test verifies that it's possible to do multiple requests as long +// as the sessionTranscript doesn't change. +// +TEST_P(UserAuthTests, MultipleRequestsSameSessionTranscript) { + provisionData(); + setupRetrieveData(); + + // First we try with a stale authToken + // + auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken + 61 * 1000); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_FALSE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); + + // Then we get a new authToken and try again. + tie(authToken, verificationToken) = mintTokens(0, // challengeForAuthToken + 5 * 1000); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_TRUE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); +} + +// Like MultipleRequestsSameSessionTranscript but we change the sessionTranscript +// between the two calls. This test verifies that change is detected and the +// second request fails. +// +TEST_P(UserAuthTests, MultipleRequestsSessionTranscriptChanges) { + provisionData(); + setupRetrieveData(); + + // First we try with a stale authToken + // + auto [authToken, verificationToken] = mintTokens(0, // challengeForAuthToken + 61 * 1000); // ageOfAuthTokenMilliSeconds + retrieveData(authToken, verificationToken, true /* expectSuccess */, + true /* useSessionTranscript */); + EXPECT_FALSE(canGetUserAuthPerSession_); + EXPECT_FALSE(canGetUserAuthTimeout_); + EXPECT_TRUE(canGetAccessibleByAll_); + EXPECT_FALSE(canGetAccessibleByNone_); + + // Then we get a new authToken and try again. + tie(authToken, verificationToken) = mintTokens(0, // challengeForAuthToken + 5 * 1000); // ageOfAuthTokenMilliSeconds + + // Change sessionTranscript... + optional> eKeyPairNew = support::createEcKeyPair(); + optional> ePublicKeyNew = support::ecKeyPairGetPublicKey(eKeyPairNew.value()); + sessionTranscript_ = calcSessionTranscript(ePublicKeyNew.value()); + + // ... and expect failure. + retrieveData(authToken, verificationToken, false /* expectSuccess */, + true /* useSessionTranscript */); +} + +INSTANTIATE_TEST_SUITE_P( + Identity, UserAuthTests, + testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)), + android::PrintInstanceNameToString); + +} // namespace android::hardware::identity diff --git a/identity/aidl/vts/VtsAttestationTests.cpp b/identity/aidl/vts/VtsAttestationTests.cpp index 00b5893d47..c7cdfc7714 100644 --- a/identity/aidl/vts/VtsAttestationTests.cpp +++ b/identity/aidl/vts/VtsAttestationTests.cpp @@ -61,51 +61,6 @@ class VtsAttestationTests : public testing::TestWithParam { sp credentialStore_; }; -TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeEmptyId) { - Status result; - - HardwareInformation hwInfo; - ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); - - sp writableCredential; - ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); - - vector attestationChallenge; - vector attestationCertificate; - vector attestationApplicationId = {}; - result = writableCredential->getAttestationCertificate( - attestationApplicationId, attestationChallenge, &attestationCertificate); - - ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() - << endl; - - EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge, - attestationApplicationId, hwInfo)); -} - -TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeNonemptyId) { - Status result; - - HardwareInformation hwInfo; - ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk()); - - sp writableCredential; - ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_)); - - vector attestationChallenge; - vector attestationCertificate; - string applicationId = "Attestation Verification"; - vector attestationApplicationId = {applicationId.begin(), applicationId.end()}; - - result = writableCredential->getAttestationCertificate( - attestationApplicationId, attestationChallenge, &attestationCertificate); - - ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() - << endl; - EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge, - attestationApplicationId, hwInfo)); -} - TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeEmptyId) { Status result; diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp index 464ab0c6d0..e347654d9a 100644 --- a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp +++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp @@ -27,15 +27,18 @@ #include #include #include +#include #include "VtsIdentityTestUtils.h" namespace android::hardware::identity { using std::endl; +using std::make_tuple; using std::map; using std::optional; using std::string; +using std::tuple; using std::vector; using ::android::sp; @@ -66,6 +69,61 @@ TEST_P(IdentityAidl, hardwareInformation) { ASSERT_GE(info.dataChunkSize, 256); } +tuple, vector> extractFromTestCredentialData( + const vector& credentialData) { + string docType; + vector storageKey; + vector credentialPrivKey; + + auto [item, _, message] = cppbor::parse(credentialData); + if (item == nullptr) { + return make_tuple(false, docType, storageKey, credentialPrivKey); + } + + const cppbor::Array* arrayItem = item->asArray(); + if (arrayItem == nullptr || arrayItem->size() != 3) { + return make_tuple(false, docType, storageKey, credentialPrivKey); + } + + const cppbor::Tstr* docTypeItem = (*arrayItem)[0]->asTstr(); + const cppbor::Bool* testCredentialItem = + ((*arrayItem)[1]->asSimple() != nullptr ? ((*arrayItem)[1]->asSimple()->asBool()) + : nullptr); + const cppbor::Bstr* encryptedCredentialKeysItem = (*arrayItem)[2]->asBstr(); + if (docTypeItem == nullptr || testCredentialItem == nullptr || + encryptedCredentialKeysItem == nullptr) { + return make_tuple(false, docType, storageKey, credentialPrivKey); + } + + docType = docTypeItem->value(); + + vector hardwareBoundKey = support::getTestHardwareBoundKey(); + const vector& encryptedCredentialKeys = encryptedCredentialKeysItem->value(); + const vector docTypeVec(docType.begin(), docType.end()); + optional> decryptedCredentialKeys = + support::decryptAes128Gcm(hardwareBoundKey, encryptedCredentialKeys, docTypeVec); + if (!decryptedCredentialKeys) { + return make_tuple(false, docType, storageKey, credentialPrivKey); + } + + auto [dckItem, dckPos, dckMessage] = cppbor::parse(decryptedCredentialKeys.value()); + if (dckItem == nullptr) { + return make_tuple(false, docType, storageKey, credentialPrivKey); + } + const cppbor::Array* dckArrayItem = dckItem->asArray(); + if (dckArrayItem == nullptr || dckArrayItem->size() != 2) { + return make_tuple(false, docType, storageKey, credentialPrivKey); + } + const cppbor::Bstr* storageKeyItem = (*dckArrayItem)[0]->asBstr(); + const cppbor::Bstr* credentialPrivKeyItem = (*dckArrayItem)[1]->asBstr(); + if (storageKeyItem == nullptr || credentialPrivKeyItem == nullptr) { + return make_tuple(false, docType, storageKey, credentialPrivKey); + } + storageKey = storageKeyItem->value(); + credentialPrivKey = credentialPrivKeyItem->value(); + return make_tuple(true, docType, storageKey, credentialPrivKey); +} + TEST_P(IdentityAidl, createAndRetrieveCredential) { // First, generate a key-pair for the reader since its public key will be // part of the request data. @@ -155,6 +213,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature) .isOk()); + // Validate the proofOfProvisioning which was returned optional> proofOfProvisioning = support::coseSignGetPayload(proofOfProvisioningSignature); ASSERT_TRUE(proofOfProvisioning); @@ -215,6 +274,22 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { credentialPubKey.value())); writableCredential = nullptr; + // Extract doctype, storage key, and credentialPrivKey from credentialData... this works + // only because we asked for a test-credential meaning that the HBK is all zeroes. + auto [exSuccess, exDocType, exStorageKey, exCredentialPrivKey] = + extractFromTestCredentialData(credentialData); + ASSERT_TRUE(exSuccess); + ASSERT_EQ(exDocType, "org.iso.18013-5.2019.mdl"); + // ... check that the public key derived from the private key matches what was + // in the certificate. + optional> exCredentialKeyPair = + support::ecPrivateKeyToKeyPair(exCredentialPrivKey); + ASSERT_TRUE(exCredentialKeyPair); + optional> exCredentialPubKey = + support::ecKeyPairGetPublicKey(exCredentialKeyPair.value()); + ASSERT_TRUE(exCredentialPubKey); + ASSERT_EQ(exCredentialPubKey.value(), credentialPubKey.value()); + // Now that the credential has been provisioned, read it back and check the // correct data is returned. sp credential; @@ -244,7 +319,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { cppbor::Array sessionTranscript = cppbor::Array() .add(cppbor::Semantic(24, deviceEngagementBytes)) .add(cppbor::Semantic(24, eReaderPubBytes)); - vector sessionTranscriptBytes = sessionTranscript.encode(); + vector sessionTranscriptEncoded = sessionTranscript.encode(); vector itemsRequestBytes = cppbor::Map("nameSpaces", @@ -272,14 +347,17 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { " },\n" "}", cborPretty); - vector dataToSign = cppbor::Array() - .add("ReaderAuthentication") - .add(sessionTranscript.clone()) - .add(cppbor::Semantic(24, itemsRequestBytes)) - .encode(); + vector encodedReaderAuthentication = + cppbor::Array() + .add("ReaderAuthentication") + .add(sessionTranscript.clone()) + .add(cppbor::Semantic(24, itemsRequestBytes)) + .encode(); + vector encodedReaderAuthenticationBytes = + cppbor::Semantic(24, encodedReaderAuthentication).encode(); optional> readerSignature = - support::coseSignEcDsa(readerKey, {}, // content - dataToSign, // detached content + support::coseSignEcDsa(readerKey, {}, // content + encodedReaderAuthenticationBytes, // detached content readerCertificate.value()); ASSERT_TRUE(readerSignature); @@ -287,15 +365,33 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { vector signingKeyBlob; Certificate signingKeyCertificate; ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk()); + optional> signingPubKey = + support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate); + EXPECT_TRUE(signingPubKey); + + // Since we're using a test-credential we know storageKey meaning we can get the + // private key. Do this, derive the public key from it, and check this matches what + // is in the certificate... + const vector exDocTypeVec(exDocType.begin(), exDocType.end()); + optional> exSigningPrivKey = + support::decryptAes128Gcm(exStorageKey, signingKeyBlob, exDocTypeVec); + ASSERT_TRUE(exSigningPrivKey); + optional> exSigningKeyPair = + support::ecPrivateKeyToKeyPair(exSigningPrivKey.value()); + ASSERT_TRUE(exSigningKeyPair); + optional> exSigningPubKey = + support::ecKeyPairGetPublicKey(exSigningKeyPair.value()); + ASSERT_TRUE(exSigningPubKey); + ASSERT_EQ(exSigningPubKey.value(), signingPubKey.value()); vector requestedNamespaces = test_utils::buildRequestNamespaces(testEntries); // OK to fail, not available in v1 HAL - credential->setRequestedNamespaces(requestedNamespaces).isOk(); + credential->setRequestedNamespaces(requestedNamespaces); // OK to fail, not available in v1 HAL credential->setVerificationToken(verificationToken); ASSERT_TRUE(credential ->startRetrieval(secureProfiles.value(), authToken, itemsRequestBytes, - signingKeyBlob, sessionTranscriptBytes, + signingKeyBlob, sessionTranscriptEncoded, readerSignature.value(), testEntriesEntryCounts) .isOk()); @@ -316,6 +412,9 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { content.insert(content.end(), chunk.begin(), chunk.end()); } EXPECT_EQ(content, entry.valueCbor); + + // TODO: also use |exStorageKey| to decrypt data and check it's the same as whatt + // the HAL returns... } vector mac; @@ -336,7 +435,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { " },\n" "}", cborPretty); - // The data that is MACed is ["DeviceAuthentication", sessionTranscriptBytes, docType, + // The data that is MACed is ["DeviceAuthentication", sessionTranscript, docType, // deviceNameSpacesBytes] so build up that structure cppbor::Array deviceAuthentication; deviceAuthentication.add("DeviceAuthentication"); @@ -345,24 +444,80 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) { string docType = "org.iso.18013-5.2019.mdl"; deviceAuthentication.add(docType); deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes)); - vector encodedDeviceAuthentication = deviceAuthentication.encode(); - optional> signingPublicKey = - support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate); - EXPECT_TRUE(signingPublicKey); - + vector deviceAuthenticationBytes = + cppbor::Semantic(24, deviceAuthentication.encode()).encode(); // Derive the key used for MACing. optional> readerEphemeralPrivateKey = support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value()); optional> sharedSecret = - support::ecdh(signingPublicKey.value(), readerEphemeralPrivateKey.value()); + support::ecdh(signingPubKey.value(), readerEphemeralPrivateKey.value()); ASSERT_TRUE(sharedSecret); + // Mix-in SessionTranscriptBytes + vector sessionTranscriptBytes = + cppbor::Semantic(24, sessionTranscript.encode()).encode(); + vector sharedSecretWithSessionTranscriptBytes = sharedSecret.value(); + std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(), + std::back_inserter(sharedSecretWithSessionTranscriptBytes)); vector salt = {0x00}; vector info = {}; - optional> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32); + optional> derivedKey = + support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32); ASSERT_TRUE(derivedKey); optional> calculatedMac = - support::coseMac0(derivedKey.value(), {}, // payload - encodedDeviceAuthentication); // detached content + support::coseMac0(derivedKey.value(), {}, // payload + deviceAuthenticationBytes); // detached content + ASSERT_TRUE(calculatedMac); + EXPECT_EQ(mac, calculatedMac); + + // Also perform an additional empty request. This is what mDL applications + // are envisioned to do - one call to get the data elements, another to get + // an empty DeviceSignedItems and corresponding MAC. + // + credential->setRequestedNamespaces({}); // OK to fail, not available in v1 HAL + ASSERT_TRUE(credential + ->startRetrieval( + secureProfiles.value(), authToken, {}, // itemsRequestBytes + signingKeyBlob, sessionTranscriptEncoded, {}, // readerSignature, + testEntriesEntryCounts) + .isOk()); + ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk()); + cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {}); + ASSERT_EQ("{}", cborPretty); + // Calculate DeviceAuthentication and MAC (MACing key hasn't changed) + deviceAuthentication = cppbor::Array(); + deviceAuthentication.add("DeviceAuthentication"); + deviceAuthentication.add(sessionTranscript.clone()); + deviceAuthentication.add(docType); + deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes)); + deviceAuthenticationBytes = cppbor::Semantic(24, deviceAuthentication.encode()).encode(); + calculatedMac = support::coseMac0(derivedKey.value(), {}, // payload + deviceAuthenticationBytes); // detached content + ASSERT_TRUE(calculatedMac); + EXPECT_EQ(mac, calculatedMac); + + // Some mDL apps might send a request but with a single empty + // namespace. Check that too. + RequestNamespace emptyRequestNS; + emptyRequestNS.namespaceName = "PersonalData"; + credential->setRequestedNamespaces({emptyRequestNS}); // OK to fail, not available in v1 HAL + ASSERT_TRUE(credential + ->startRetrieval( + secureProfiles.value(), authToken, {}, // itemsRequestBytes + signingKeyBlob, sessionTranscriptEncoded, {}, // readerSignature, + testEntriesEntryCounts) + .isOk()); + ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk()); + cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {}); + ASSERT_EQ("{}", cborPretty); + // Calculate DeviceAuthentication and MAC (MACing key hasn't changed) + deviceAuthentication = cppbor::Array(); + deviceAuthentication.add("DeviceAuthentication"); + deviceAuthentication.add(sessionTranscript.clone()); + deviceAuthentication.add(docType); + deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes)); + deviceAuthenticationBytes = cppbor::Semantic(24, deviceAuthentication.encode()).encode(); + calculatedMac = support::coseMac0(derivedKey.value(), {}, // payload + deviceAuthenticationBytes); // detached content ASSERT_TRUE(calculatedMac); EXPECT_EQ(mac, calculatedMac); } diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp index 8b0c050226..b572b0fbec 100644 --- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp +++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp @@ -69,11 +69,10 @@ TEST_P(IdentityCredentialTests, verifyAttestationWithEmptyChallenge) { result = writableCredential->getAttestationCertificate( attestationApplicationId, attestationChallenge, &attestationCertificate); - EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() - << endl; - - EXPECT_TRUE(test_utils::validateAttestationCertificate( - attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo)); + EXPECT_FALSE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() + << endl; + EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, result.exceptionCode()); + EXPECT_EQ(IIdentityCredentialStore::STATUS_INVALID_DATA, result.serviceSpecificErrorCode()); } TEST_P(IdentityCredentialTests, verifyAttestationSuccessWithChallenge) { @@ -130,6 +129,7 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalization) { // First call should go through const vector entryCounts = {2, 4}; + writableCredential->setExpectedProofOfProvisioningSize(123456); result = writableCredential->startPersonalization(5, entryCounts); ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; @@ -151,18 +151,8 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) { // Verify minimal number of profile count and entry count const vector entryCounts = {1, 1}; - writableCredential->startPersonalization(1, entryCounts); - EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() - << endl; -} - -TEST_P(IdentityCredentialTests, verifyStartPersonalizationZero) { - Status result; - sp writableCredential; - ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); - - const vector entryCounts = {0}; - writableCredential->startPersonalization(0, entryCounts); + writableCredential->setExpectedProofOfProvisioningSize(123456); + result = writableCredential->startPersonalization(1, entryCounts); EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; } @@ -174,7 +164,8 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) { // Verify minimal number of profile count and entry count const vector entryCounts = {1}; - writableCredential->startPersonalization(1, entryCounts); + writableCredential->setExpectedProofOfProvisioningSize(123456); + result = writableCredential->startPersonalization(1, entryCounts); EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; } @@ -186,7 +177,8 @@ TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) { // Verify set a large number of profile count and entry count is ok const vector entryCounts = {3000}; - writableCredential->startPersonalization(3500, entryCounts); + writableCredential->setExpectedProofOfProvisioningSize(123456); + result = writableCredential->startPersonalization(25, entryCounts); EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; } @@ -198,7 +190,8 @@ TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) { // Enter mismatched entry and profile numbers const vector entryCounts = {5, 6}; - writableCredential->startPersonalization(5, entryCounts); + writableCredential->setExpectedProofOfProvisioningSize(123456); + result = writableCredential->startPersonalization(5, entryCounts); ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; @@ -234,7 +227,8 @@ TEST_P(IdentityCredentialTests, verifyDuplicateProfileId) { ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); const vector entryCounts = {3, 6}; - writableCredential->startPersonalization(3, entryCounts); + writableCredential->setExpectedProofOfProvisioningSize(123456); + result = writableCredential->startPersonalization(3, entryCounts); ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; @@ -251,9 +245,10 @@ TEST_P(IdentityCredentialTests, verifyDuplicateProfileId) { SecureAccessControlProfile profile; Certificate cert; cert.encodedCertificate = testProfile.readerCertificate; + int64_t secureUserId = testProfile.userAuthenticationRequired ? 66 : 0; result = writableCredential->addAccessControlProfile( testProfile.id, cert, testProfile.userAuthenticationRequired, - testProfile.timeoutMillis, 0, &profile); + testProfile.timeoutMillis, secureUserId, &profile); if (expectOk) { expectOk = false; @@ -554,7 +549,7 @@ TEST_P(IdentityCredentialTests, verifyEmptyNameSpaceMixedWithNonEmptyWorks) { ; // OK to fail, not available in v1 HAL writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize); - writableCredential->startPersonalization(3, entryCounts); + result = writableCredential->startPersonalization(3, entryCounts); ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; @@ -608,7 +603,8 @@ TEST_P(IdentityCredentialTests, verifyInterleavingEntryNameSpaceOrderingFails) { // before "Image" and 2 after image, which is not correct. All of same name // space should occur together. Let's see if this fails. const vector entryCounts = {2u, 1u, 2u}; - writableCredential->startPersonalization(3, entryCounts); + writableCredential->setExpectedProofOfProvisioningSize(123456); + result = writableCredential->startPersonalization(3, entryCounts); ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; @@ -674,6 +670,7 @@ TEST_P(IdentityCredentialTests, verifyAccessControlProfileIdOutOfRange) { ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_)); const vector entryCounts = {1}; + writableCredential->setExpectedProofOfProvisioningSize(123456); Status result = writableCredential->startPersonalization(1, entryCounts); ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage() << endl; diff --git a/identity/aidl/vts/VtsIdentityTestUtils.cpp b/identity/aidl/vts/VtsIdentityTestUtils.cpp index aaebcbe3c9..b6ed80f4b1 100644 --- a/identity/aidl/vts/VtsIdentityTestUtils.cpp +++ b/identity/aidl/vts/VtsIdentityTestUtils.cpp @@ -96,9 +96,10 @@ optional> addAccessControlProfiles( SecureAccessControlProfile profile; Certificate cert; cert.encodedCertificate = testProfile.readerCertificate; + int64_t secureUserId = testProfile.userAuthenticationRequired ? 66 : 0; result = writableCredential->addAccessControlProfile( testProfile.id, cert, testProfile.userAuthenticationRequired, - testProfile.timeoutMillis, 0, &profile); + testProfile.timeoutMillis, secureUserId, &profile); // Don't use assert so all errors can be outputed. Then return // instead of exit even on errors so caller can decide. diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h index 507e914fa3..f7ec7c516f 100644 --- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h +++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h @@ -33,6 +33,7 @@ using ::std::optional; using ::std::string; using ::std::tuple; using ::std::vector; +using ::std::pair; // --------------------------------------------------------------------------- // Miscellaneous utilities. @@ -119,6 +120,12 @@ optional> encryptAes128Gcm(const vector& key, const vec optional, vector>>> createEcKeyPairAndAttestation( const vector& challenge, const vector& applicationId); +// Like createEcKeyPairAndAttestation() but allows you to choose the public key. +// +optional>> createAttestationForEcPublicKey( + const vector& publicKey, const vector& challenge, + const vector& applicationId); + // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the // PKCS#8 encoded key-pair. // @@ -134,6 +141,11 @@ optional> ecKeyPairGetPublicKey(const vector& keyPair); // optional> ecKeyPairGetPrivateKey(const vector& keyPair); +// Creates a PKCS#8 encoded key-pair from a private key (which must be uncompressed, +// e.g. 32 bytes). The public key is derived from the given private key.. +// +optional> ecPrivateKeyToKeyPair(const vector& privateKey); + // For an EC key |keyPair| encoded in PKCS#8 format, creates a PKCS#12 structure // with the key-pair (not using a password to encrypt the data). The public key // in the created structure is included as a certificate, using the given fields @@ -150,6 +162,12 @@ optional> ecKeyPairGetPkcs12(const vector& keyPair, con // optional> signEcDsa(const vector& key, const vector& data); +// Like signEcDsa() but instead of taking the data to be signed, takes a digest +// of it instead. +// +optional> signEcDsaDigest(const vector& key, + const vector& dataDigest); + // Calculates the HMAC with SHA-256 for |data| using |key|. The calculated HMAC // is returned and will be 32 bytes. // @@ -170,6 +188,27 @@ bool checkEcDsaSignature(const vector& digest, const vector& s // optional> certificateChainGetTopMostKey(const vector& certificateChain); +// Extracts the public-key from the top-most certificate in |certificateChain| +// (which should be a concatenated chain of DER-encoded X.509 certificates). +// +// Return offset and size of the public-key +// +optional> certificateFindPublicKey(const vector& x509Certificate); + +// Extracts the TbsCertificate from the top-most certificate in |certificateChain| +// (which should be a concatenated chain of DER-encoded X.509 certificates). +// +// Return offset and size of the TbsCertificate +// +optional> certificateTbsCertificate(const vector& x509Certificate); + +// Extracts the Signature from the top-most certificate in |certificateChain| +// (which should be a concatenated chain of DER-encoded X.509 certificates). +// +// Return offset and size of the Signature +// +optional> certificateFindSignature(const vector& x509Certificate); + // Generates a X.509 certificate for |publicKey| (which must be in the format // returned by ecKeyPairGetPublicKey()). // @@ -226,6 +265,11 @@ optional>> certificateChainSplit(const vector& c // bool certificateChainValidate(const vector& certificateChain); +// Returns true if |certificate| is signed by |publicKey|. +// +bool certificateSignedByPublicKey(const vector& certificate, + const vector& publicKey); + // Signs |data| and |detachedContent| with |key| (which must be in the format // returned by ecKeyPairGetPrivateKey()). // @@ -238,6 +282,21 @@ optional> coseSignEcDsa(const vector& key, const vector const vector& detachedContent, const vector& certificateChain); +// Creates a COSE_Signature1 where |signatureToBeSigned| is the ECDSA signature +// of the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process". +// +// The |signatureToBeSigned| is expected to be 64 bytes and contain the R value, +// then the S value. +// +// The |data| parameter will be included in the COSE_Sign1 CBOR. +// +// If |certificateChain| is non-empty it's included in the 'x5chain' +// protected header element (as as described in'draft-ietf-cose-x509-04'). +// +optional> coseSignEcDsaWithSignature(const vector& signatureToBeSigned, + const vector& data, + const vector& certificateChain); + // Checks that |signatureCoseSign1| (in COSE_Sign1 format) is a valid signature // made with |public_key| (which must be in the format returned by // ecKeyPairGetPublicKey()) where |detachedContent| is the detached content. @@ -246,9 +305,23 @@ bool coseCheckEcDsaSignature(const vector& signatureCoseSign1, const vector& detachedContent, const vector& publicKey); +// Converts a DER-encoded signature to the format used in 'signature' bstr in COSE_Sign1. +bool ecdsaSignatureDerToCose(const vector& ecdsaDerSignature, + vector& ecdsaCoseSignature); + +// Converts from the format in in 'signature' bstr in COSE_Sign1 to DER encoding. +bool ecdsaSignatureCoseToDer(const vector& ecdsaCoseSignature, + vector& ecdsaDerSignature); + // Extracts the payload from a COSE_Sign1. optional> coseSignGetPayload(const vector& signatureCoseSign1); +// Extracts the signature (of the ToBeSigned CBOR) from a COSE_Sign1. +optional> coseSignGetSignature(const vector& signatureCoseSign1); + +// Extracts the signature algorithm from a COSE_Sign1. +optional coseSignGetAlg(const vector& signatureCoseSign1); + // Extracts the X.509 certificate chain, if present. Returns the data as a // concatenated chain of DER-encoded X.509 certificates // @@ -264,6 +337,16 @@ optional> coseSignGetX5Chain(const vector& signatureCos optional> coseMac0(const vector& key, const vector& data, const vector& detachedContent); +// Creates a COSE_Mac0 where |digestToBeMaced| is the HMAC-SHA256 +// of the ToBeMaced CBOR from RFC 8051 "6.3. How to Compute and Verify a MAC". +// +// The |digestToBeMaced| is expected to be 32 bytes. +// +// The |data| parameter will be included in the COSE_Mac0 CBOR. +// +optional> coseMacWithDigest(const vector& digestToBeMaced, + const vector& data); + // --------------------------------------------------------------------------- // Utility functions specific to IdentityCredential. // --------------------------------------------------------------------------- diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp index dc49ddc992..8e099e7d2f 100644 --- a/identity/support/src/IdentityCredentialSupport.cpp +++ b/identity/support/src/IdentityCredentialSupport.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -684,6 +685,48 @@ static bool parseX509Certificates(const vector& certificateChain, return true; } +bool certificateSignedByPublicKey(const vector& certificate, + const vector& publicKey) { + const unsigned char* p = certificate.data(); + auto x509 = X509_Ptr(d2i_X509(nullptr, &p, certificate.size())); + if (x509 == nullptr) { + LOG(ERROR) << "Error parsing X509 certificate"; + return false; + } + + auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); + auto point = EC_POINT_Ptr(EC_POINT_new(group.get())); + if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) != + 1) { + LOG(ERROR) << "Error decoding publicKey"; + return false; + } + auto ecKey = EC_KEY_Ptr(EC_KEY_new()); + auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); + if (ecKey.get() == nullptr || pkey.get() == nullptr) { + LOG(ERROR) << "Memory allocation failed"; + return false; + } + if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) { + LOG(ERROR) << "Error setting group"; + return false; + } + if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) { + LOG(ERROR) << "Error setting point"; + return false; + } + if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) { + LOG(ERROR) << "Error setting key"; + return false; + } + + if (X509_verify(x509.get(), pkey.get()) != 1) { + return false; + } + + return true; +} + // TODO: Right now the only check we perform is to check that each certificate // is signed by its successor. We should - but currently don't - also check // things like valid dates etc. @@ -770,7 +813,8 @@ vector sha256(const vector& data) { return ret; } -optional> signEcDsa(const vector& key, const vector& data) { +optional> signEcDsaDigest(const vector& key, + const vector& dataDigest) { auto bn = BIGNUM_Ptr(BN_bin2bn(key.data(), key.size(), nullptr)); if (bn.get() == nullptr) { LOG(ERROR) << "Error creating BIGNUM"; @@ -783,8 +827,7 @@ optional> signEcDsa(const vector& key, const vector> signEcDsa(const vector& key, const vector> signEcDsa(const vector& key, const vector& data) { + return signEcDsaDigest(key, sha256(data)); +} + optional> hmacSha256(const vector& key, const vector& data) { HMAC_CTX ctx; HMAC_CTX_init(&ctx); @@ -955,6 +1002,51 @@ optional, vector>>> createEcKeyPairAnd return make_pair(keyPair, attestationCert.value()); } +optional>> createAttestationForEcPublicKey( + const vector& publicKey, const vector& challenge, + const vector& applicationId) { + auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); + auto point = EC_POINT_Ptr(EC_POINT_new(group.get())); + if (EC_POINT_oct2point(group.get(), point.get(), publicKey.data(), publicKey.size(), nullptr) != + 1) { + LOG(ERROR) << "Error decoding publicKey"; + return {}; + } + auto ecKey = EC_KEY_Ptr(EC_KEY_new()); + auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); + if (ecKey.get() == nullptr || pkey.get() == nullptr) { + LOG(ERROR) << "Memory allocation failed"; + return {}; + } + if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) { + LOG(ERROR) << "Error setting group"; + return {}; + } + if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) { + LOG(ERROR) << "Error setting point"; + return {}; + } + if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) { + LOG(ERROR) << "Error setting key"; + return {}; + } + + uint64_t now = (std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()). + count()/ 1000000000); + uint64_t secondsInOneYear = 365 * 24 * 60 * 60; + uint64_t expireTimeMs = (now + secondsInOneYear) * 1000; + + optional>> attestationCert = + createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs); + if (!attestationCert) { + LOG(ERROR) << "Error create attestation from key and challenge"; + return {}; + } + + return attestationCert.value(); +} + optional> createEcKeyPair() { auto ec_key = EC_KEY_Ptr(EC_KEY_new()); auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); @@ -1047,6 +1139,42 @@ optional> ecKeyPairGetPrivateKey(const vector& keyPair) return privateKey; } +optional> ecPrivateKeyToKeyPair(const vector& privateKey) { + auto bn = BIGNUM_Ptr(BN_bin2bn(privateKey.data(), privateKey.size(), nullptr)); + if (bn.get() == nullptr) { + LOG(ERROR) << "Error creating BIGNUM"; + return {}; + } + + auto ecKey = EC_KEY_Ptr(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + if (EC_KEY_set_private_key(ecKey.get(), bn.get()) != 1) { + LOG(ERROR) << "Error setting private key from BIGNUM"; + return {}; + } + + auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new()); + if (pkey.get() == nullptr) { + LOG(ERROR) << "Memory allocation failed"; + return {}; + } + + if (EVP_PKEY_set1_EC_KEY(pkey.get(), ecKey.get()) != 1) { + LOG(ERROR) << "Error getting private key"; + return {}; + } + + int size = i2d_PrivateKey(pkey.get(), nullptr); + if (size == 0) { + LOG(ERROR) << "Error generating public key encoding"; + return {}; + } + vector keyPair; + keyPair.resize(size); + unsigned char* p = keyPair.data(); + i2d_PrivateKey(pkey.get(), &p); + return keyPair; +} + optional> ecKeyPairGetPkcs12(const vector& keyPair, const string& name, const string& serialDecimal, const string& issuer, const string& subject, time_t validityNotBefore, @@ -1441,6 +1569,120 @@ optional> certificateChainGetTopMostKey(const vector& c return publicKey; } +optional> certificateFindPublicKey(const vector& x509Certificate) { + vector certs; + if (!parseX509Certificates(x509Certificate, certs)) { + return {}; + } + if (certs.size() < 1) { + LOG(ERROR) << "No certificates in chain"; + return {}; + } + + auto pkey = EVP_PKEY_Ptr(X509_get_pubkey(certs[0].get())); + if (pkey.get() == nullptr) { + LOG(ERROR) << "No public key"; + return {}; + } + + auto ecKey = EC_KEY_Ptr(EVP_PKEY_get1_EC_KEY(pkey.get())); + if (ecKey.get() == nullptr) { + LOG(ERROR) << "Failed getting EC key"; + return {}; + } + + auto ecGroup = EC_KEY_get0_group(ecKey.get()); + auto ecPoint = EC_KEY_get0_public_key(ecKey.get()); + int size = EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, + nullptr); + if (size == 0) { + LOG(ERROR) << "Error generating public key encoding"; + return {}; + } + vector publicKey; + publicKey.resize(size); + EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(), + publicKey.size(), nullptr); + + size_t publicKeyOffset = 0; + size_t publicKeySize = (size_t)size; + void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(), + (const void*)publicKey.data(), publicKey.size()); + + if (location == NULL) { + LOG(ERROR) << "Error finding publicKey from x509Certificate"; + return {}; + } + publicKeyOffset = (size_t)((const char*)location - (const char*)x509Certificate.data()); + + return std::make_pair(publicKeyOffset, publicKeySize); +} + +optional> certificateTbsCertificate(const vector& x509Certificate) { + vector certs; + if (!parseX509Certificates(x509Certificate, certs)) { + return {}; + } + if (certs.size() < 1) { + LOG(ERROR) << "No certificates in chain"; + return {}; + } + + unsigned char* buf = NULL; + int len = i2d_re_X509_tbs(certs[0].get(), &buf); + if ((len < 0) || (buf == NULL)) { + LOG(ERROR) << "fail to extract tbsCertificate in x509Certificate"; + return {}; + } + + vector tbsCertificate(len); + memcpy(tbsCertificate.data(), buf, len); + + size_t tbsCertificateOffset = 0; + size_t tbsCertificateSize = (size_t)len; + void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(), + (const void*)tbsCertificate.data(), tbsCertificate.size()); + + if (location == NULL) { + LOG(ERROR) << "Error finding tbsCertificate from x509Certificate"; + return {}; + } + tbsCertificateOffset = (size_t)((const char*)location - (const char*)x509Certificate.data()); + + return std::make_pair(tbsCertificateOffset, tbsCertificateSize); +} + +optional> certificateFindSignature(const vector& x509Certificate) { + vector certs; + if (!parseX509Certificates(x509Certificate, certs)) { + return {}; + } + if (certs.size() < 1) { + LOG(ERROR) << "No certificates in chain"; + return {}; + } + + ASN1_BIT_STRING* psig; + X509_ALGOR* palg; + X509_get0_signature((const ASN1_BIT_STRING**)&psig, (const X509_ALGOR**)&palg, certs[0].get()); + + vector signature(psig->length); + memcpy(signature.data(), psig->data, psig->length); + + size_t signatureOffset = 0; + size_t signatureSize = (size_t)psig->length; + void* location = memmem((const void*)x509Certificate.data(), x509Certificate.size(), + (const void*)signature.data(), signature.size()); + + if (location == NULL) { + LOG(ERROR) << "Error finding signature from x509Certificate"; + return {}; + } + signatureOffset = (size_t)((const char*)location - (const char*)x509Certificate.data()); + + return std::make_pair(signatureOffset, signatureSize); +} + // --------------------------------------------------------------------------- // COSE Utility Functions // --------------------------------------------------------------------------- @@ -1538,6 +1780,55 @@ bool ecdsaSignatureDerToCose(const vector& ecdsaDerSignature, return true; } +optional> coseSignEcDsaWithSignature(const vector& signatureToBeSigned, + const vector& data, + const vector& certificateChain) { + if (signatureToBeSigned.size() != 64) { + LOG(ERROR) << "Invalid size for signatureToBeSigned, expected 64 got " + << signatureToBeSigned.size(); + return {}; + } + + cppbor::Map unprotectedHeaders; + cppbor::Map protectedHeaders; + + protectedHeaders.add(COSE_LABEL_ALG, COSE_ALG_ECDSA_256); + + if (certificateChain.size() != 0) { + optional>> certs = support::certificateChainSplit(certificateChain); + if (!certs) { + LOG(ERROR) << "Error splitting certificate chain"; + return {}; + } + if (certs.value().size() == 1) { + unprotectedHeaders.add(COSE_LABEL_X5CHAIN, certs.value()[0]); + } else { + cppbor::Array certArray; + for (const vector& cert : certs.value()) { + certArray.add(cert); + } + unprotectedHeaders.add(COSE_LABEL_X5CHAIN, std::move(certArray)); + } + } + + vector encodedProtectedHeaders = coseEncodeHeaders(protectedHeaders); + + cppbor::Array coseSign1; + coseSign1.add(encodedProtectedHeaders); + coseSign1.add(std::move(unprotectedHeaders)); + if (data.size() == 0) { + cppbor::Null nullValue; + coseSign1.add(std::move(nullValue)); + } else { + coseSign1.add(data); + } + coseSign1.add(signatureToBeSigned); + vector signatureCoseSign1; + signatureCoseSign1 = coseSign1.encode(); + + return signatureCoseSign1; +} + optional> coseSignEcDsa(const vector& key, const vector& data, const vector& detachedContent, const vector& certificateChain) { @@ -1673,6 +1964,35 @@ bool coseCheckEcDsaSignature(const vector& signatureCoseSign1, return true; } +// Extracts the signature (of the ToBeSigned CBOR) from a COSE_Sign1. +optional> coseSignGetSignature(const vector& signatureCoseSign1) { + auto [item, _, message] = cppbor::parse(signatureCoseSign1); + if (item == nullptr) { + LOG(ERROR) << "Passed-in COSE_Sign1 is not valid CBOR: " << message; + return {}; + } + const cppbor::Array* array = item->asArray(); + if (array == nullptr) { + LOG(ERROR) << "Value for COSE_Sign1 is not an array"; + return {}; + } + if (array->size() != 4) { + LOG(ERROR) << "Value for COSE_Sign1 is not an array of size 4"; + return {}; + } + + vector signature; + const cppbor::Bstr* signatureAsBstr = (*array)[3]->asBstr(); + if (signatureAsBstr == nullptr) { + LOG(ERROR) << "Value for signature is not a bstr"; + return {}; + } + // Copy payload into |data| + signature = signatureAsBstr->value(); + + return signature; +} + optional> coseSignGetPayload(const vector& signatureCoseSign1) { auto [item, _, message] = cppbor::parse(signatureCoseSign1); if (item == nullptr) { @@ -1710,6 +2030,59 @@ optional> coseSignGetPayload(const vector& signatureCos return data; } +optional coseSignGetAlg(const vector& signatureCoseSign1) { + auto [item, _, message] = cppbor::parse(signatureCoseSign1); + if (item == nullptr) { + LOG(ERROR) << "Passed-in COSE_Sign1 is not valid CBOR: " << message; + return {}; + } + const cppbor::Array* array = item->asArray(); + if (array == nullptr) { + LOG(ERROR) << "Value for COSE_Sign1 is not an array"; + return {}; + } + if (array->size() != 4) { + LOG(ERROR) << "Value for COSE_Sign1 is not an array of size 4"; + return {}; + } + + const cppbor::Bstr* protectedHeadersBytes = (*array)[0]->asBstr(); + if (protectedHeadersBytes == nullptr) { + LOG(ERROR) << "Value for protectedHeaders is not a bstr"; + return {}; + } + auto [item2, _2, message2] = cppbor::parse(protectedHeadersBytes->value()); + if (item2 == nullptr) { + LOG(ERROR) << "Error parsing protectedHeaders: " << message2; + return {}; + } + const cppbor::Map* protectedHeaders = item2->asMap(); + if (protectedHeaders == nullptr) { + LOG(ERROR) << "Decoded CBOR for protectedHeaders is not a map"; + return {}; + } + + for (size_t n = 0; n < protectedHeaders->size(); n++) { + auto [keyItem, valueItem] = (*protectedHeaders)[n]; + const cppbor::Int* number = keyItem->asInt(); + if (number == nullptr) { + LOG(ERROR) << "Key item in top-level map is not a number"; + return {}; + } + int label = number->value(); + if (label == COSE_LABEL_ALG) { + const cppbor::Int* number = valueItem->asInt(); + if (number != nullptr) { + return number->value(); + } + LOG(ERROR) << "Value for COSE_LABEL_ALG label is not a number"; + return {}; + } + } + LOG(ERROR) << "Did not find COSE_LABEL_ALG label in protected headers"; + return {}; +} + optional> coseSignGetX5Chain(const vector& signatureCoseSign1) { auto [item, _, message] = cppbor::parse(signatureCoseSign1); if (item == nullptr) { @@ -1825,6 +2198,28 @@ optional> coseMac0(const vector& key, const vector> coseMacWithDigest(const vector& digestToBeMaced, + const vector& data) { + cppbor::Map unprotectedHeaders; + cppbor::Map protectedHeaders; + + protectedHeaders.add(COSE_LABEL_ALG, COSE_ALG_HMAC_256_256); + + vector encodedProtectedHeaders = coseEncodeHeaders(protectedHeaders); + + cppbor::Array array; + array.add(encodedProtectedHeaders); + array.add(std::move(unprotectedHeaders)); + if (data.size() == 0) { + cppbor::Null nullValue; + array.add(std::move(nullValue)); + } else { + array.add(data); + } + array.add(digestToBeMaced); + return array.encode(); +} + // --------------------------------------------------------------------------- // Utility functions specific to IdentityCredential. // --------------------------------------------------------------------------- diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp index 366cd0e553..bcfa75729a 100644 --- a/keymaster/4.0/support/keymaster_utils.cpp +++ b/keymaster/4.0/support/keymaster_utils.cpp @@ -121,8 +121,8 @@ void appendUint64(std::vector& vec, uint64_t value) { uint64_t extractUint64(const std::vector& data, size_t offset) { uint64_t value = 0; for (size_t n = 0; n < sizeof(uint64_t); n++) { - uint8_t byte = data[offset + n]; - value |= byte << (n * 8); + uint64_t tmp = data[offset + n]; + value |= (tmp << (n * 8)); } return value; } @@ -137,8 +137,8 @@ void appendUint32(std::vector& vec, uint32_t value) { uint32_t extractUint32(const std::vector& data, size_t offset) { uint32_t value = 0; for (size_t n = 0; n < sizeof(uint32_t); n++) { - uint8_t byte = data[offset + n]; - value |= byte << (n * 8); + uint32_t tmp = data[offset + n]; + value |= (tmp << (n * 8)); } return value; } diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp index 6cbe4dafae..aa2de2a682 100644 --- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp +++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp @@ -438,10 +438,10 @@ bool verify_attestation_record(const string& challenge, const string& app_id, EXPECT_TRUE(device_locked); } - // Check that the expected result from VBMeta matches the build type. Only a user build - // should have AVB reporting the device is locked. - EXPECT_NE(property_get("ro.build.type", property_value, ""), 0); - if (!strcmp(property_value, "user")) { + // Check that the device is locked if not debuggable, e.g., user build + // images in CTS. For VTS, debuggable images are used to allow adb root + // and the device is unlocked. + if (!property_get_bool("ro.debuggable", false)) { EXPECT_TRUE(device_locked); } else { EXPECT_FALSE(device_locked); diff --git a/media/omx/1.0/vts/functional/common/Android.bp b/media/omx/1.0/vts/functional/common/Android.bp index 2c024a0c0c..720ea9f1cf 100644 --- a/media/omx/1.0/vts/functional/common/Android.bp +++ b/media/omx/1.0/vts/functional/common/Android.bp @@ -74,5 +74,6 @@ cc_defaults { // TODO(b/64437680): Assume these libs are always available on the device. shared_libs: [ "libstagefright_foundation", + "libstagefright_omx_utils", ], } diff --git a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp index 9b4722ec57..68ee90093f 100644 --- a/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp +++ b/media/omx/1.0/vts/functional/master/VtsHalMediaOmxV1_0TargetMasterTest.cpp @@ -33,6 +33,7 @@ #include #include #include +#include using ::android::sp; using ::android::base::Join; @@ -87,71 +88,6 @@ void displayComponentInfo(hidl_vec& nodeList) { } } -/* - * Returns the role based on is_encoder and mime. - * - * The mapping from a pair (is_encoder, mime) to a role string is - * defined in frameworks/av/media/libmedia/MediaDefs.cpp and - * frameworks/av/media/libstagefright/omx/OMXUtils.cpp. This function - * does essentially the same work as GetComponentRole() in - * OMXUtils.cpp. - * - * Args: - * is_encoder: A boolean indicating whether the role is for an - * encoder or a decoder. - * mime: A string of the desired mime type. - * - * Returns: - * A const string for the requested role name, empty if mime is not - * recognized. - */ -const std::string getComponentRole(bool isEncoder, const std::string mime) { - // Mapping from mime types to roles. - // These values come from MediaDefs.cpp and OMXUtils.cpp - const std::map audioMimeToRole = { - {"3gpp", "amrnb"}, {"ac3", "ac3"}, {"amr-wb", "amrwb"}, - {"eac3", "eac3"}, {"flac", "flac"}, {"g711-alaw", "g711alaw"}, - {"g711-mlaw", "g711mlaw"}, {"gsm", "gsm"}, {"mp4a-latm", "aac"}, - {"mpeg", "mp3"}, {"mpeg-L1", "mp1"}, {"mpeg-L2", "mp2"}, - {"opus", "opus"}, {"raw", "raw"}, {"vorbis", "vorbis"}, - }; - const std::map videoMimeToRole = { - {"3gpp", "h263"}, {"avc", "avc"}, {"dolby-vision", "dolby-vision"}, - {"hevc", "hevc"}, {"mp4v-es", "mpeg4"}, {"mpeg2", "mpeg2"}, - {"x-vnd.on2.vp8", "vp8"}, {"x-vnd.on2.vp9", "vp9"}, - }; - const std::map imageMimeToRole = { - {"vnd.android.heic", "heic"}, - }; - - // Suffix begins after the mime prefix. - const size_t prefixEnd = mime.find("/"); - if (prefixEnd == std::string::npos || prefixEnd == mime.size()) return ""; - const std::string mime_suffix = mime.substr(prefixEnd + 1, mime.size() - 1); - const std::string middle = isEncoder ? "encoder." : "decoder."; - std::string prefix; - std::string suffix; - if (mime.rfind("audio/", 0) != std::string::npos) { - const auto it = audioMimeToRole.find(mime_suffix); - if (it == audioMimeToRole.end()) return ""; - prefix = "audio_"; - suffix = it->second; - } else if (mime.rfind("video/", 0) != std::string::npos) { - const auto it = videoMimeToRole.find(mime_suffix); - if (it == videoMimeToRole.end()) return ""; - prefix = "video_"; - suffix = it->second; - } else if (mime.rfind("image/", 0) != std::string::npos) { - const auto it = imageMimeToRole.find(mime_suffix); - if (it == imageMimeToRole.end()) return ""; - prefix = "image_"; - suffix = it->second; - } else { - return ""; - } - return prefix + middle + suffix; -} - void validateAttributes( const std::map& knownPatterns, const std::vector& unknownPatterns, @@ -315,7 +251,7 @@ TEST_P(MasterHidlTest, ListRoles) { }; // Matching rules for node names and owners - const testing::internal::RE nodeNamePattern = "[a-zA-Z0-9.-]+"; + const testing::internal::RE nodeNamePattern = "[a-zA-Z0-9._-]+"; const testing::internal::RE nodeOwnerPattern = "[a-zA-Z0-9._-]+"; std::set roleKeys; @@ -328,7 +264,8 @@ TEST_P(MasterHidlTest, ListRoles) { // Make sure role name follows expected format based on type and // isEncoder - const std::string role_name = getComponentRole(role.isEncoder, role.type); + const std::string role_name( + ::android::GetComponentRole(role.isEncoder, role.type.c_str())); EXPECT_EQ(role_name, role.role) << "Role \"" << role.role << "\" does not match " << (role.isEncoder ? "an encoder " : "a decoder ") << "for mime type \"" << role.type << "."; diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp index 87e851930d..d802911234 100644 --- a/neuralnetworks/1.0/vts/functional/Android.bp +++ b/neuralnetworks/1.0/vts/functional/Android.bp @@ -62,11 +62,12 @@ cc_test { defaults: ["neuralnetworks_vts_functional_defaults"], srcs: [ "BasicTests.cpp", + "GeneratedTestHarness.cpp", "TestAssertions.cpp", + "TestMain.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", "VtsHalNeuralnetworks.cpp", - "GeneratedTestHarness.cpp", ], shared_libs: [ "libfmq", diff --git a/neuralnetworks/1.0/vts/functional/AndroidTest.xml b/neuralnetworks/1.0/vts/functional/AndroidTest.xml index 54e6e91da4..13671f92b8 100644 --- a/neuralnetworks/1.0/vts/functional/AndroidTest.xml +++ b/neuralnetworks/1.0/vts/functional/AndroidTest.xml @@ -26,10 +26,6 @@ - - diff --git a/neuralnetworks/1.0/vts/functional/TestMain.cpp b/neuralnetworks/1.0/vts/functional/TestMain.cpp new file mode 100644 index 0000000000..6bf4e5fab1 --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/TestMain.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "1.0/LogTestCaseToLogcat.h" + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + testing::UnitTest::GetInstance()->listeners().Append( + new android::hardware::neuralnetworks::LogTestCaseToLogcat()); + return RUN_ALL_TESTS(); +} diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/LogTestCaseToLogcat.h b/neuralnetworks/1.0/vts/functional/include/1.0/LogTestCaseToLogcat.h new file mode 100644 index 0000000000..f1413ef1aa --- /dev/null +++ b/neuralnetworks/1.0/vts/functional/include/1.0/LogTestCaseToLogcat.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_LOG_TEST_CASE_TO_LOGCAT_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_LOG_TEST_CASE_TO_LOGCAT_H + +#include +#include + +namespace android::hardware::neuralnetworks { + +class LogTestCaseToLogcat : public ::testing::EmptyTestEventListener { + public: + void OnTestStart(const ::testing::TestInfo& test_info) override { + LOG(INFO) << "[Test Case] " << test_info.test_suite_name() << "." << test_info.name() + << " BEGIN"; + } + + void OnTestEnd(const ::testing::TestInfo& test_info) override { + LOG(INFO) << "[Test Case] " << test_info.test_suite_name() << "." << test_info.name() + << " END"; + } +}; + +} // namespace android::hardware::neuralnetworks + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_LOG_TEST_CASE_TO_LOGCAT_H diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp index 9afa0af35b..405548fe55 100644 --- a/neuralnetworks/1.1/vts/functional/Android.bp +++ b/neuralnetworks/1.1/vts/functional/Android.bp @@ -20,6 +20,7 @@ cc_test { srcs: [ "BasicTests.cpp", "TestAssertions.cpp", + "TestMain.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", "VtsHalNeuralnetworks.cpp", diff --git a/neuralnetworks/1.1/vts/functional/AndroidTest.xml b/neuralnetworks/1.1/vts/functional/AndroidTest.xml index a6f812fe1e..cfde60cca4 100644 --- a/neuralnetworks/1.1/vts/functional/AndroidTest.xml +++ b/neuralnetworks/1.1/vts/functional/AndroidTest.xml @@ -26,10 +26,6 @@ - - diff --git a/neuralnetworks/1.1/vts/functional/TestMain.cpp b/neuralnetworks/1.1/vts/functional/TestMain.cpp new file mode 100644 index 0000000000..6bf4e5fab1 --- /dev/null +++ b/neuralnetworks/1.1/vts/functional/TestMain.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "1.0/LogTestCaseToLogcat.h" + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + testing::UnitTest::GetInstance()->listeners().Append( + new android::hardware::neuralnetworks::LogTestCaseToLogcat()); + return RUN_ALL_TESTS(); +} diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp index 182f716115..93edca6126 100644 --- a/neuralnetworks/1.2/vts/functional/Android.bp +++ b/neuralnetworks/1.2/vts/functional/Android.bp @@ -40,6 +40,7 @@ cc_test { "CompilationCachingTests.cpp", "GeneratedTestHarness.cpp", "TestAssertions.cpp", + "TestMain.cpp", "ValidateBurst.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", diff --git a/neuralnetworks/1.2/vts/functional/AndroidTest.xml b/neuralnetworks/1.2/vts/functional/AndroidTest.xml index adbdf40da3..3f91618920 100644 --- a/neuralnetworks/1.2/vts/functional/AndroidTest.xml +++ b/neuralnetworks/1.2/vts/functional/AndroidTest.xml @@ -26,10 +26,6 @@ - - diff --git a/neuralnetworks/1.2/vts/functional/TestMain.cpp b/neuralnetworks/1.2/vts/functional/TestMain.cpp new file mode 100644 index 0000000000..6bf4e5fab1 --- /dev/null +++ b/neuralnetworks/1.2/vts/functional/TestMain.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "1.0/LogTestCaseToLogcat.h" + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + testing::UnitTest::GetInstance()->listeners().Append( + new android::hardware::neuralnetworks::LogTestCaseToLogcat()); + return RUN_ALL_TESTS(); +} diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h index d01336eccd..c4e2b15d1c 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "1.0/Utils.h" #include "1.2/Callbacks.h" diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index 39ea4c24f2..3b2b14c98c 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -5102,11 +5102,15 @@ enum OperationType : int32_t { * The inputs and outputs of the two referenced subgraphs must agree with the * signature of this operation. That is, if the operation has (3 + n) inputs * and m outputs, both subgraphs must have n inputs and m outputs with the same - * types as the corresponding operation inputs and outputs. + * types, ranks, dimensions, scales, + * zeroPoints, and extraParams as the corresponding operation inputs and + * outputs. + * All of the operands mentioned must have fully specified dimensions. * * Inputs: * * 0: A value of type {@link OperandType::TENSOR_BOOL8} and shape [1] * that determines which of the two referenced subgraphs to execute. + * The operand must have fully specified dimensions. * * 1: A {@link OperandType::SUBGRAPH} reference to the subgraph to be * executed if the condition is true. * * 2: A {@link OperandType::SUBGRAPH} reference to the subgraph to be @@ -5165,13 +5169,17 @@ enum OperationType : int32_t { * Inputs: * * 0: A {@link OperandType::SUBGRAPH} reference to the condition * subgraph. The subgraph must have (m + k + n) inputs with - * the same types as the corresponding inputs of the WHILE operation - * and exactly one output of {@link OperandType::TENSOR_BOOL8} - * and shape [1]. + * the same types, ranks, dimensions, + * scales, zeroPoints, and extraParams as the corresponding inputs of + * the WHILE operation and exactly one output of + * {@link OperandType::TENSOR_BOOL8} and shape [1]. + * All of the operands mentioned must have fully specified dimensions. * * 1: A {@link OperandType::SUBGRAPH} reference to the body subgraph. * The subgraph must have (m + k + n) inputs and (m + k) outputs with - * the same types as the corresponding inputs and outputs of the WHILE - * operation. + * the same types, ranks, dimensions, + * scales, zeroPoints, and extraParams as the corresponding inputs and + * outputs of the WHILE operation. + * All of the operands mentioned must have fully specified dimensions. * * (m inputs): Initial values for input-output operands. * * (k inputs): Initial values for state-only operands. * * (n inputs): Values for input-only operands. @@ -5491,7 +5499,9 @@ struct Operand { * If a tensor operand's dimensions are not fully specified, the * dimensions of the operand are deduced from the operand * dimensions and values of the operation for which that operand - * is an output. + * is an output or from the corresponding {@link OperationType::IF} or + * {@link OperationType::WHILE} operation input operand dimensions in the + * case of referenced subgraph input operands. * * In the following situations, a tensor operand's dimensions must * be fully specified: @@ -5499,8 +5509,8 @@ struct Operand { * . The operand has lifetime CONSTANT_COPY or * CONSTANT_REFERENCE. * - * . The operand has lifetime SUBGRAPH_INPUT. Fully - * specified dimensions must either be present in the + * . The operand has lifetime SUBGRAPH_INPUT and belongs to the main + * subgraph. Fully specified dimensions must either be present in the * Operand or they must be provided in the corresponding * RequestArgument. * EXCEPTION: If the input is optional and omitted diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t index 0a6e45e487..7220e372a7 100644 --- a/neuralnetworks/1.3/types.t +++ b/neuralnetworks/1.3/types.t @@ -264,7 +264,9 @@ struct Operand { * If a tensor operand's dimensions are not fully specified, the * dimensions of the operand are deduced from the operand * dimensions and values of the operation for which that operand - * is an output. + * is an output or from the corresponding {@link OperationType::IF} or + * {@link OperationType::WHILE} operation input operand dimensions in the + * case of referenced subgraph input operands. * * In the following situations, a tensor operand's dimensions must * be fully specified: @@ -272,8 +274,8 @@ struct Operand { * . The operand has lifetime CONSTANT_COPY or * CONSTANT_REFERENCE. * - * . The operand has lifetime SUBGRAPH_INPUT. Fully - * specified dimensions must either be present in the + * . The operand has lifetime SUBGRAPH_INPUT and belongs to the main + * subgraph. Fully specified dimensions must either be present in the * Operand or they must be provided in the corresponding * RequestArgument. * EXCEPTION: If the input is optional and omitted diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp index 771fc54e0d..b17d44559b 100644 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ b/neuralnetworks/1.3/vts/functional/Android.bp @@ -43,6 +43,7 @@ cc_test { "MemoryDomainTests.cpp", "QualityOfServiceTests.cpp", "TestAssertions.cpp", + "TestMain.cpp", "ValidateBurst.cpp", "ValidateModel.cpp", "ValidateRequest.cpp", diff --git a/neuralnetworks/1.3/vts/functional/AndroidTest.xml b/neuralnetworks/1.3/vts/functional/AndroidTest.xml index 30cff2e9fa..e5acd90a9c 100644 --- a/neuralnetworks/1.3/vts/functional/AndroidTest.xml +++ b/neuralnetworks/1.3/vts/functional/AndroidTest.xml @@ -26,10 +26,6 @@ - - diff --git a/neuralnetworks/1.3/vts/functional/TestMain.cpp b/neuralnetworks/1.3/vts/functional/TestMain.cpp new file mode 100644 index 0000000000..6bf4e5fab1 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/TestMain.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "1.0/LogTestCaseToLogcat.h" + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + testing::UnitTest::GetInstance()->listeners().Append( + new android::hardware::neuralnetworks::LogTestCaseToLogcat()); + return RUN_ALL_TESTS(); +} diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h index de082c39cc..a2e5071d97 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "1.0/Utils.h" #include "1.3/Callbacks.h" diff --git a/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp b/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp index 125ea0cce6..8e6cf860af 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include using namespace ::android::hardware::radio::V1_0; @@ -22,6 +23,7 @@ using namespace ::android::hardware::radio::V1_0; * Test IRadio.setGsmBroadcastConfig() for the response returned. */ TEST_P(RadioHidlTest, setGsmBroadcastConfig) { + LOG(DEBUG) << "setGsmBroadcastConfig"; serial = GetRandomSerialNumber(); // Create GsmBroadcastSmsConfigInfo #1 @@ -79,12 +81,14 @@ TEST_P(RadioHidlTest, setGsmBroadcastConfig) { RadioError::INVALID_MODEM_STATE, RadioError::INVALID_STATE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setGsmBroadcastConfig finished"; } /* * Test IRadio.getGsmBroadcastConfig() for the response returned. */ TEST_P(RadioHidlTest, getGsmBroadcastConfig) { + LOG(DEBUG) << "getGsmBroadcastConfig"; serial = GetRandomSerialNumber(); radio->getGsmBroadcastConfig(serial); @@ -99,12 +103,14 @@ TEST_P(RadioHidlTest, getGsmBroadcastConfig) { {RadioError::NONE, RadioError::INVALID_MODEM_STATE, RadioError::INVALID_STATE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getGsmBroadcastConfig finished"; } /* * Test IRadio.setCdmaBroadcastConfig() for the response returned. */ TEST_P(RadioHidlTest, setCdmaBroadcastConfig) { + LOG(DEBUG) << "setCdmaBroadcastConfig"; serial = GetRandomSerialNumber(); CdmaBroadcastSmsConfigInfo cbSmsConfig; @@ -126,12 +132,14 @@ TEST_P(RadioHidlTest, setCdmaBroadcastConfig) { {RadioError::NONE, RadioError::INVALID_MODEM_STATE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setCdmaBroadcastConfig finished"; } /* * Test IRadio.getCdmaBroadcastConfig() for the response returned. */ TEST_P(RadioHidlTest, getCdmaBroadcastConfig) { + LOG(DEBUG) << "getCdmaBroadcastConfig"; serial = GetRandomSerialNumber(); radio->getCdmaBroadcastConfig(serial); @@ -144,12 +152,14 @@ TEST_P(RadioHidlTest, getCdmaBroadcastConfig) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getCdmaBroadcastConfig finished"; } /* * Test IRadio.setCdmaBroadcastActivation() for the response returned. */ TEST_P(RadioHidlTest, setCdmaBroadcastActivation) { + LOG(DEBUG) << "setCdmaBroadcastActivation"; serial = GetRandomSerialNumber(); bool activate = false; @@ -164,12 +174,14 @@ TEST_P(RadioHidlTest, setCdmaBroadcastActivation) { {RadioError::NONE, RadioError::INVALID_ARGUMENTS}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setCdmaBroadcastActivation finished"; } /* * Test IRadio.setGsmBroadcastActivation() for the response returned. */ TEST_P(RadioHidlTest, setGsmBroadcastActivation) { + LOG(DEBUG) << "setGsmBroadcastActivation"; serial = GetRandomSerialNumber(); bool activate = false; @@ -186,4 +198,5 @@ TEST_P(RadioHidlTest, setGsmBroadcastActivation) { RadioError::INVALID_STATE, RadioError::OPERATION_NOT_ALLOWED}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setGsmBroadcastActivation finished"; } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_data.cpp b/radio/1.0/vts/functional/radio_hidl_hal_data.cpp index d937d74403..e3ee9d4ff3 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_data.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_data.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include using namespace ::android::hardware::radio::V1_0; @@ -22,6 +23,7 @@ using namespace ::android::hardware::radio::V1_0; * Test IRadio.getDataRegistrationState() for the response returned. */ TEST_P(RadioHidlTest, getDataRegistrationState) { + LOG(DEBUG) << "getDataRegistrationState"; serial = GetRandomSerialNumber(); radio->getDataRegistrationState(serial); @@ -94,12 +96,14 @@ TEST_P(RadioHidlTest, getDataRegistrationState) { } } } + LOG(DEBUG) << "getDataRegistrationState finished"; } /* * Test IRadio.setupDataCall() for the response returned. */ TEST_P(RadioHidlTest, setupDataCall) { + LOG(DEBUG) << "setupDataCall"; serial = GetRandomSerialNumber(); RadioTechnology radioTechnology = RadioTechnology::LTE; @@ -142,12 +146,14 @@ TEST_P(RadioHidlTest, setupDataCall) { RadioError::RADIO_NOT_AVAILABLE, RadioError::SIM_ABSENT}, CHECK_OEM_ERROR)); } + LOG(DEBUG) << "setupDataCall finished"; } /* * Test IRadio.deactivateDataCall() for the response returned. */ TEST_P(RadioHidlTest, deactivateDataCall) { + LOG(DEBUG) << "deactivateDataCall"; serial = GetRandomSerialNumber(); int cid = 1; bool reasonRadioShutDown = false; @@ -164,12 +170,14 @@ TEST_P(RadioHidlTest, deactivateDataCall) { RadioError::SIM_ABSENT, RadioError::INVALID_CALL_ID}, CHECK_OEM_ERROR)); } + LOG(DEBUG) << "deactivateDataCall finished"; } /* * Test IRadio.getDataCallList() for the response returned. */ TEST_P(RadioHidlTest, getDataCallList) { + LOG(DEBUG) << "getDataCallList"; serial = GetRandomSerialNumber(); radio->getDataCallList(serial); @@ -183,12 +191,14 @@ TEST_P(RadioHidlTest, getDataCallList) { radioRsp->rspInfo.error, {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::SIM_ABSENT})); } + LOG(DEBUG) << "getDataCallList finished"; } /* * Test IRadio.setInitialAttachApn() for the response returned. */ TEST_P(RadioHidlTest, setInitialAttachApn) { + LOG(DEBUG) << "setInitialAttachApn"; serial = GetRandomSerialNumber(); DataProfileInfo dataProfileInfo; @@ -226,12 +236,14 @@ TEST_P(RadioHidlTest, setInitialAttachApn) { RadioError::SUBSCRIPTION_NOT_AVAILABLE}, CHECK_OEM_ERROR)); } + LOG(DEBUG) << "setInitialAttachApn finished"; } /* * Test IRadio.setDataAllowed() for the response returned. */ TEST_P(RadioHidlTest, setDataAllowed) { + LOG(DEBUG) << "setDataAllowed"; serial = GetRandomSerialNumber(); bool allow = true; @@ -244,12 +256,14 @@ TEST_P(RadioHidlTest, setDataAllowed) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "setDataAllowed finished"; } /* * Test IRadio.setDataProfile() for the response returned. */ TEST_P(RadioHidlTest, setDataProfile) { + LOG(DEBUG) << "setDataProfile"; serial = GetRandomSerialNumber(); // Create a dataProfileInfo @@ -289,4 +303,5 @@ TEST_P(RadioHidlTest, setDataProfile) { {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::SIM_ABSENT, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "setDataProfile finished"; } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp index 9568524f4f..8a977a91e1 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp @@ -14,22 +14,26 @@ * limitations under the License. */ +#include #include /* * Test IRadio.getIccCardStatus() for the response returned. */ TEST_P(RadioHidlTest, getIccCardStatus) { + LOG(DEBUG) << "getIccCardStatus"; EXPECT_LE(cardStatus.applications.size(), (unsigned int)RadioConst::CARD_MAX_APPS); EXPECT_LT(cardStatus.gsmUmtsSubscriptionAppIndex, (int)RadioConst::CARD_MAX_APPS); EXPECT_LT(cardStatus.cdmaSubscriptionAppIndex, (int)RadioConst::CARD_MAX_APPS); EXPECT_LT(cardStatus.imsSubscriptionAppIndex, (int)RadioConst::CARD_MAX_APPS); + LOG(DEBUG) << "getIccCardStatus finished"; } /* * Test IRadio.supplyIccPinForApp() for the response returned */ TEST_P(RadioHidlTest, supplyIccPinForApp) { + LOG(DEBUG) << "supplyIccPinForApp"; serial = GetRandomSerialNumber(); // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and @@ -49,12 +53,14 @@ TEST_P(RadioHidlTest, supplyIccPinForApp) { {RadioError::PASSWORD_INCORRECT, RadioError::REQUEST_NOT_SUPPORTED})); } } + LOG(DEBUG) << "supplyIccPinForApp finished"; } /* * Test IRadio.supplyIccPukForApp() for the response returned. */ TEST_P(RadioHidlTest, supplyIccPukForApp) { + LOG(DEBUG) << "supplyIccPukForApp"; serial = GetRandomSerialNumber(); // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and @@ -73,12 +79,14 @@ TEST_P(RadioHidlTest, supplyIccPukForApp) { RadioError::INVALID_SIM_STATE})); } } + LOG(DEBUG) << "supplyIccPukForApp finished"; } /* * Test IRadio.supplyIccPin2ForApp() for the response returned. */ TEST_P(RadioHidlTest, supplyIccPin2ForApp) { + LOG(DEBUG) << "supplyIccPin2ForApp"; serial = GetRandomSerialNumber(); // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and @@ -99,12 +107,14 @@ TEST_P(RadioHidlTest, supplyIccPin2ForApp) { RadioError::SIM_PUK2})); } } + LOG(DEBUG) << "supplyIccPin2ForApp finished"; } /* * Test IRadio.supplyIccPuk2ForApp() for the response returned. */ TEST_P(RadioHidlTest, supplyIccPuk2ForApp) { + LOG(DEBUG) << "supplyIccPuk2ForApp"; serial = GetRandomSerialNumber(); // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and @@ -123,12 +133,14 @@ TEST_P(RadioHidlTest, supplyIccPuk2ForApp) { RadioError::INVALID_SIM_STATE})); } } + LOG(DEBUG) << "supplyIccPuk2ForApp finished"; } /* * Test IRadio.changeIccPinForApp() for the response returned. */ TEST_P(RadioHidlTest, changeIccPinForApp) { + LOG(DEBUG) << "changeIccPinForApp"; serial = GetRandomSerialNumber(); // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and @@ -148,12 +160,14 @@ TEST_P(RadioHidlTest, changeIccPinForApp) { {RadioError::PASSWORD_INCORRECT, RadioError::REQUEST_NOT_SUPPORTED})); } } + LOG(DEBUG) << "changeIccPinForApp finished"; } /* * Test IRadio.changeIccPin2ForApp() for the response returned. */ TEST_P(RadioHidlTest, changeIccPin2ForApp) { + LOG(DEBUG) << "changeIccPin2ForApp"; serial = GetRandomSerialNumber(); // Pass wrong password and check PASSWORD_INCORRECT returned for 3GPP and @@ -174,6 +188,7 @@ TEST_P(RadioHidlTest, changeIccPin2ForApp) { RadioError::SIM_PUK2})); } } + LOG(DEBUG) << "changeIccPin2ForApp finished"; } /* @@ -182,6 +197,7 @@ TEST_P(RadioHidlTest, changeIccPin2ForApp) { * Test IRadio.getImsiForApp() for the response returned. */ TEST_P(RadioHidlTest, DISABLED_getImsiForApp) { + LOG(DEBUG) << "DISABLED_getImsiForApp"; serial = GetRandomSerialNumber(); // Check success returned while getting imsi for 3GPP and 3GPP2 apps only @@ -205,12 +221,14 @@ TEST_P(RadioHidlTest, DISABLED_getImsiForApp) { } } } + LOG(DEBUG) << "DISABLED_getImsiForApp finished"; } /* * Test IRadio.iccIOForApp() for the response returned. */ TEST_P(RadioHidlTest, iccIOForApp) { + LOG(DEBUG) << "iccIOForApp"; serial = GetRandomSerialNumber(); for (int i = 0; i < (int)cardStatus.applications.size(); i++) { @@ -230,12 +248,14 @@ TEST_P(RadioHidlTest, iccIOForApp) { EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type); EXPECT_EQ(serial, radioRsp->rspInfo.serial); } + LOG(DEBUG) << "iccIOForApp finished"; } /* * Test IRadio.iccTransmitApduBasicChannel() for the response returned. */ TEST_P(RadioHidlTest, iccTransmitApduBasicChannel) { + LOG(DEBUG) << "iccTransmitApduBasicChannel"; serial = GetRandomSerialNumber(); SimApdu msg; memset(&msg, 0, sizeof(msg)); @@ -247,12 +267,14 @@ TEST_P(RadioHidlTest, iccTransmitApduBasicChannel) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); // TODO(sanketpadawe): Add test for error code + LOG(DEBUG) << "iccTransmitApduBasicChannel finished"; } /* * Test IRadio.iccOpenLogicalChannel() for the response returned. */ TEST_P(RadioHidlTest, iccOpenLogicalChannel) { + LOG(DEBUG) << "iccOpenLogicalChannel"; serial = GetRandomSerialNumber(); int p2 = 0x04; // Specified in ISO 7816-4 clause 7.1.1 0x04 means that FCP template is requested. @@ -262,12 +284,14 @@ TEST_P(RadioHidlTest, iccOpenLogicalChannel) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type); } + LOG(DEBUG) << "iccOpenLogicalChannel finished"; } /* * Test IRadio.iccCloseLogicalChannel() for the response returned. */ TEST_P(RadioHidlTest, iccCloseLogicalChannel) { + LOG(DEBUG) << "iccCloseLogicalChannel"; serial = GetRandomSerialNumber(); // Try closing invalid channel and check INVALID_ARGUMENTS returned as error radio->iccCloseLogicalChannel(serial, 0); @@ -276,12 +300,14 @@ TEST_P(RadioHidlTest, iccCloseLogicalChannel) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); EXPECT_EQ(RadioError::INVALID_ARGUMENTS, radioRsp->rspInfo.error); + LOG(DEBUG) << "iccCloseLogicalChannel finished"; } /* * Test IRadio.iccTransmitApduLogicalChannel() for the response returned. */ TEST_P(RadioHidlTest, iccTransmitApduLogicalChannel) { + LOG(DEBUG) << "iccTransmitApduLogicalChannel"; serial = GetRandomSerialNumber(); SimApdu msg; memset(&msg, 0, sizeof(msg)); @@ -293,12 +319,14 @@ TEST_P(RadioHidlTest, iccTransmitApduLogicalChannel) { EXPECT_EQ(serial, radioRsp->rspInfo.serial); // TODO(sanketpadawe): Add test for error code + LOG(DEBUG) << "iccTransmitApduLogicalChannel finished"; } /* * Test IRadio.requestIccSimAuthentication() for the response returned. */ TEST_P(RadioHidlTest, requestIccSimAuthentication) { + LOG(DEBUG) << "requestIccSimAuthentication"; serial = GetRandomSerialNumber(); // Pass wrong challenge string and check RadioError::INVALID_ARGUMENTS @@ -312,12 +340,14 @@ TEST_P(RadioHidlTest, requestIccSimAuthentication) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "requestIccSimAuthentication finished"; } /* * Test IRadio.supplyNetworkDepersonalization() for the response returned. */ TEST_P(RadioHidlTest, supplyNetworkDepersonalization) { + LOG(DEBUG) << "supplyNetworkDepersonalization"; serial = GetRandomSerialNumber(); radio->supplyNetworkDepersonalization(serial, hidl_string("test")); @@ -332,4 +362,5 @@ TEST_P(RadioHidlTest, supplyNetworkDepersonalization) { RadioError::INVALID_SIM_STATE, RadioError::MODEM_ERR, RadioError::NO_MEMORY, RadioError::PASSWORD_INCORRECT, RadioError::SIM_ABSENT, RadioError::SYSTEM_ERR})); } + LOG(DEBUG) << "supplyNetworkDepersonalization finished"; } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp index 7228fb086b..3f964732f6 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp @@ -14,12 +14,14 @@ * limitations under the License. */ +#include #include /* * Test IRadio.getSignalStrength() for the response returned. */ TEST_P(RadioHidlTest, getSignalStrength) { + LOG(DEBUG) << "getSignalStrength"; serial = GetRandomSerialNumber(); radio->getSignalStrength(serial); @@ -30,12 +32,14 @@ TEST_P(RadioHidlTest, getSignalStrength) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getSignalStrength finished"; } /* * Test IRadio.getVoiceRegistrationState() for the response returned. */ TEST_P(RadioHidlTest, getVoiceRegistrationState) { + LOG(DEBUG) << "getVoiceRegistrationState"; serial = GetRandomSerialNumber(); radio->getVoiceRegistrationState(serial); @@ -46,12 +50,14 @@ TEST_P(RadioHidlTest, getVoiceRegistrationState) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getVoiceRegistrationState finished"; } /* * Test IRadio.getOperator() for the response returned. */ TEST_P(RadioHidlTest, getOperator) { + LOG(DEBUG) << "getOperator"; serial = GetRandomSerialNumber(); radio->getOperator(serial); @@ -62,12 +68,14 @@ TEST_P(RadioHidlTest, getOperator) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getOperator finished"; } /* * Test IRadio.setRadioPower() for the response returned. */ TEST_P(RadioHidlTest, setRadioPower) { + LOG(DEBUG) << "setRadioPower"; serial = GetRandomSerialNumber(); radio->setRadioPower(serial, 1); @@ -78,12 +86,14 @@ TEST_P(RadioHidlTest, setRadioPower) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "setRadioPower finished"; } /* * Test IRadio.getNetworkSelectionMode() for the response returned. */ TEST_P(RadioHidlTest, getNetworkSelectionMode) { + LOG(DEBUG) << "getNetworkSelectionMode"; serial = GetRandomSerialNumber(); radio->getNetworkSelectionMode(serial); @@ -94,12 +104,14 @@ TEST_P(RadioHidlTest, getNetworkSelectionMode) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getNetworkSelectionMode finished"; } /* * Test IRadio.setNetworkSelectionModeAutomatic() for the response returned. */ TEST_P(RadioHidlTest, setNetworkSelectionModeAutomatic) { + LOG(DEBUG) << "setNetworkSelectionModeAutomatic"; serial = GetRandomSerialNumber(); radio->setNetworkSelectionModeAutomatic(serial); @@ -113,12 +125,14 @@ TEST_P(RadioHidlTest, setNetworkSelectionModeAutomatic) { {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, RadioError::OPERATION_NOT_ALLOWED}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setNetworkSelectionModeAutomatic finished"; } /* * Test IRadio.setNetworkSelectionModeManual() for the response returned. */ TEST_P(RadioHidlTest, setNetworkSelectionModeManual) { + LOG(DEBUG) << "setNetworkSelectionModeManual"; serial = GetRandomSerialNumber(); radio->setNetworkSelectionModeManual(serial, "123456"); @@ -132,12 +146,14 @@ TEST_P(RadioHidlTest, setNetworkSelectionModeManual) { RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setNetworkSelectionModeManual finished"; } /* * Test IRadio.getAvailableNetworks() for the response returned. */ TEST_P(RadioHidlTest, getAvailableNetworks) { + LOG(DEBUG) << "getAvailableNetworks"; serial = GetRandomSerialNumber(); radio->getAvailableNetworks(serial); @@ -153,12 +169,14 @@ TEST_P(RadioHidlTest, getAvailableNetworks) { RadioError::MODEM_ERR, RadioError::OPERATION_NOT_ALLOWED}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getAvailableNetworks finished"; } /* * Test IRadio.getBasebandVersion() for the response returned. */ TEST_P(RadioHidlTest, getBasebandVersion) { + LOG(DEBUG) << "getBasebandVersion"; serial = GetRandomSerialNumber(); radio->getBasebandVersion(serial); @@ -169,12 +187,14 @@ TEST_P(RadioHidlTest, getBasebandVersion) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getBasebandVersion finished"; } /* * Test IRadio.setBandMode() for the response returned. */ TEST_P(RadioHidlTest, setBandMode) { + LOG(DEBUG) << "setBandMode"; serial = GetRandomSerialNumber(); radio->setBandMode(serial, RadioBandMode::BAND_MODE_USA); @@ -186,12 +206,14 @@ TEST_P(RadioHidlTest, setBandMode) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setBandMode finished"; } /* * Test IRadio.getAvailableBandModes() for the response returned. */ TEST_P(RadioHidlTest, getAvailableBandModes) { + LOG(DEBUG) << "getAvailableBandModes"; serial = GetRandomSerialNumber(); radio->getAvailableBandModes(serial); @@ -202,12 +224,14 @@ TEST_P(RadioHidlTest, getAvailableBandModes) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getAvailableBandModes finished"; } /* * Test IRadio.setPreferredNetworkType() for the response returned. */ TEST_P(RadioHidlTest, setPreferredNetworkType) { + LOG(DEBUG) << "setPreferredNetworkType"; serial = GetRandomSerialNumber(); radio->setPreferredNetworkType(serial, PreferredNetworkType::GSM_ONLY); @@ -219,12 +243,14 @@ TEST_P(RadioHidlTest, setPreferredNetworkType) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setPreferredNetworkType finished"; } /* * Test IRadio.getPreferredNetworkType() for the response returned. */ TEST_P(RadioHidlTest, getPreferredNetworkType) { + LOG(DEBUG) << "getPreferredNetworkType"; serial = GetRandomSerialNumber(); radio->getPreferredNetworkType(serial); @@ -235,12 +261,14 @@ TEST_P(RadioHidlTest, getPreferredNetworkType) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getPreferredNetworkType finished"; } /* * Test IRadio.getNeighboringCids() for the response returned. */ TEST_P(RadioHidlTest, getNeighboringCids) { + LOG(DEBUG) << "getNeighboringCids"; serial = GetRandomSerialNumber(); radio->getNeighboringCids(serial); @@ -253,12 +281,14 @@ TEST_P(RadioHidlTest, getNeighboringCids) { {RadioError::NONE, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getNeighboringCids finished"; } /* * Test IRadio.setLocationUpdates() for the response returned. */ TEST_P(RadioHidlTest, setLocationUpdates) { + LOG(DEBUG) << "setLocationUpdates"; serial = GetRandomSerialNumber(); radio->setLocationUpdates(serial, true); @@ -270,12 +300,14 @@ TEST_P(RadioHidlTest, setLocationUpdates) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::SIM_ABSENT})); } + LOG(DEBUG) << "setLocationUpdates finished"; } /* * Test IRadio.setCdmaRoamingPreference() for the response returned. */ TEST_P(RadioHidlTest, setCdmaRoamingPreference) { + LOG(DEBUG) << "setCdmaRoamingPreference"; serial = GetRandomSerialNumber(); radio->setCdmaRoamingPreference(serial, CdmaRoamingType::HOME_NETWORK); @@ -288,12 +320,14 @@ TEST_P(RadioHidlTest, setCdmaRoamingPreference) { radioRsp->rspInfo.error, {RadioError::NONE, RadioError::SIM_ABSENT, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "setCdmaRoamingPreference finished"; } /* * Test IRadio.getCdmaRoamingPreference() for the response returned. */ TEST_P(RadioHidlTest, getCdmaRoamingPreference) { + LOG(DEBUG) << "getCdmaRoamingPreference"; serial = GetRandomSerialNumber(); radio->getCdmaRoamingPreference(serial); @@ -307,12 +341,14 @@ TEST_P(RadioHidlTest, getCdmaRoamingPreference) { {RadioError::NONE, RadioError::SIM_ABSENT, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getCdmaRoamingPreference finished"; } /* * Test IRadio.getTTYMode() for the response returned. */ TEST_P(RadioHidlTest, getTTYMode) { + LOG(DEBUG) << "getTTYMode"; serial = GetRandomSerialNumber(); radio->getTTYMode(serial); @@ -323,12 +359,14 @@ TEST_P(RadioHidlTest, getTTYMode) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getTTYMode finished"; } /* * Test IRadio.setTTYMode() for the response returned. */ TEST_P(RadioHidlTest, setTTYMode) { + LOG(DEBUG) << "setTTYMode"; serial = GetRandomSerialNumber(); radio->setTTYMode(serial, TtyMode::OFF); @@ -339,12 +377,14 @@ TEST_P(RadioHidlTest, setTTYMode) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "setTTYMode finished"; } /* * Test IRadio.setPreferredVoicePrivacy() for the response returned. */ TEST_P(RadioHidlTest, setPreferredVoicePrivacy) { + LOG(DEBUG) << "setPreferredVoicePrivacy"; serial = GetRandomSerialNumber(); radio->setPreferredVoicePrivacy(serial, true); @@ -356,12 +396,14 @@ TEST_P(RadioHidlTest, setPreferredVoicePrivacy) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "setPreferredVoicePrivacy finished"; } /* * Test IRadio.getPreferredVoicePrivacy() for the response returned. */ TEST_P(RadioHidlTest, getPreferredVoicePrivacy) { + LOG(DEBUG) << "getPreferredVoicePrivacy"; serial = GetRandomSerialNumber(); radio->getPreferredVoicePrivacy(serial); @@ -373,12 +415,14 @@ TEST_P(RadioHidlTest, getPreferredVoicePrivacy) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "getPreferredVoicePrivacy finished"; } /* * Test IRadio.getCDMASubscription() for the response returned. */ TEST_P(RadioHidlTest, getCDMASubscription) { + LOG(DEBUG) << "getCDMASubscription"; serial = GetRandomSerialNumber(); radio->getCDMASubscription(serial); @@ -391,12 +435,14 @@ TEST_P(RadioHidlTest, getCDMASubscription) { radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::SIM_ABSENT})); } + LOG(DEBUG) << "getCDMASubscription finished"; } /* * Test IRadio.getDeviceIdentity() for the response returned. */ TEST_P(RadioHidlTest, getDeviceIdentity) { + LOG(DEBUG) << "getDeviceIdentity"; serial = GetRandomSerialNumber(); radio->getDeviceIdentity(serial); @@ -408,12 +454,14 @@ TEST_P(RadioHidlTest, getDeviceIdentity) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::EMPTY_RECORD})); } + LOG(DEBUG) << "getDeviceIdentity finished"; } /* * Test IRadio.exitEmergencyCallbackMode() for the response returned. */ TEST_P(RadioHidlTest, exitEmergencyCallbackMode) { + LOG(DEBUG) << "exitEmergencyCallbackMode"; serial = GetRandomSerialNumber(); radio->exitEmergencyCallbackMode(serial); @@ -426,12 +474,14 @@ TEST_P(RadioHidlTest, exitEmergencyCallbackMode) { radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::SIM_ABSENT})); } + LOG(DEBUG) << "exitEmergencyCallbackMode finished"; } /* * Test IRadio.getCdmaSubscriptionSource() for the response returned. */ TEST_P(RadioHidlTest, getCdmaSubscriptionSource) { + LOG(DEBUG) << "getCdmaSubscriptionSource"; serial = GetRandomSerialNumber(); radio->getCdmaSubscriptionSource(serial); @@ -444,12 +494,14 @@ TEST_P(RadioHidlTest, getCdmaSubscriptionSource) { radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::SIM_ABSENT})); } + LOG(DEBUG) << "getCdmaSubscriptionSource finished"; } /* * Test IRadio.setCdmaSubscriptionSource() for the response returned. */ TEST_P(RadioHidlTest, setCdmaSubscriptionSource) { + LOG(DEBUG) << "setCdmaSubscriptionSource"; serial = GetRandomSerialNumber(); radio->setCdmaSubscriptionSource(serial, CdmaSubscriptionSource::RUIM_SIM); @@ -463,12 +515,14 @@ TEST_P(RadioHidlTest, setCdmaSubscriptionSource) { {RadioError::NONE, RadioError::SIM_ABSENT, RadioError::SUBSCRIPTION_NOT_AVAILABLE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setCdmaSubscriptionSource finished"; } /* * Test IRadio.getVoiceRadioTechnology() for the response returned. */ TEST_P(RadioHidlTest, getVoiceRadioTechnology) { + LOG(DEBUG) << "getVoiceRadioTechnology"; serial = GetRandomSerialNumber(); radio->getVoiceRadioTechnology(serial); @@ -479,12 +533,14 @@ TEST_P(RadioHidlTest, getVoiceRadioTechnology) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getVoiceRadioTechnology finished"; } /* * Test IRadio.getCellInfoList() for the response returned. */ TEST_P(RadioHidlTest, getCellInfoList) { + LOG(DEBUG) << "getCellInfoList"; serial = GetRandomSerialNumber(); radio->getCellInfoList(serial); @@ -497,12 +553,14 @@ TEST_P(RadioHidlTest, getCellInfoList) { {RadioError::NONE, RadioError::NO_NETWORK_FOUND}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getCellInfoList finished"; } /* * Test IRadio.setCellInfoListRate() for the response returned. */ TEST_P(RadioHidlTest, setCellInfoListRate) { + LOG(DEBUG) << "setCellInfoListRate"; serial = GetRandomSerialNumber(); // TODO(sanketpadawe): RIL crashes with value of rate = 10 @@ -515,12 +573,14 @@ TEST_P(RadioHidlTest, setCellInfoListRate) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "setCellInfoListRate finished"; } /* * Test IRadio.nvReadItem() for the response returned. */ TEST_P(RadioHidlTest, nvReadItem) { + LOG(DEBUG) << "nvReadItem"; serial = GetRandomSerialNumber(); radio->nvReadItem(serial, NvItem::LTE_BAND_ENABLE_25); @@ -532,12 +592,14 @@ TEST_P(RadioHidlTest, nvReadItem) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "nvReadItem finished"; } /* * Test IRadio.nvWriteItem() for the response returned. */ TEST_P(RadioHidlTest, nvWriteItem) { + LOG(DEBUG) << "nvWriteItem"; serial = GetRandomSerialNumber(); NvWriteItem item; memset(&item, 0, sizeof(item)); @@ -552,12 +614,14 @@ TEST_P(RadioHidlTest, nvWriteItem) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "nvWriteItem finished"; } /* * Test IRadio.nvWriteCdmaPrl() for the response returned. */ TEST_P(RadioHidlTest, nvWriteCdmaPrl) { + LOG(DEBUG) << "nvWriteCdmaPrl"; serial = GetRandomSerialNumber(); std::vector prl = {1, 2, 3, 4, 5}; @@ -570,12 +634,14 @@ TEST_P(RadioHidlTest, nvWriteCdmaPrl) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "nvWriteCdmaPrl finished"; } /* * Test IRadio.nvResetConfig() for the response returned. */ TEST_P(RadioHidlTest, nvResetConfig) { + LOG(DEBUG) << "nvResetConfig"; serial = GetRandomSerialNumber(); radio->nvResetConfig(serial, ResetNvType::FACTORY_RESET); @@ -587,12 +653,14 @@ TEST_P(RadioHidlTest, nvResetConfig) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "nvResetConfig finished"; } /* * Test IRadio.setUiccSubscription() for the response returned. */ TEST_P(RadioHidlTest, setUiccSubscription) { + LOG(DEBUG) << "setUiccSubscription"; serial = GetRandomSerialNumber(); SelectUiccSub item; memset(&item, 0, sizeof(item)); @@ -609,12 +677,14 @@ TEST_P(RadioHidlTest, setUiccSubscription) { RadioError::MODEM_ERR, RadioError::SUBSCRIPTION_NOT_SUPPORTED}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setUiccSubscription finished"; } /* * Test IRadio.getHardwareConfig() for the response returned. */ TEST_P(RadioHidlTest, getHardwareConfig) { + LOG(DEBUG) << "getHardwareConfig"; serial = GetRandomSerialNumber(); radio->getHardwareConfig(serial); @@ -626,6 +696,7 @@ TEST_P(RadioHidlTest, getHardwareConfig) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getHardwareConfig finished"; } /* @@ -651,6 +722,7 @@ TEST_P(RadioHidlTest, DISABLED_requestShutdown) { * Test IRadio.getRadioCapability() for the response returned. */ TEST_P(RadioHidlTest, getRadioCapability) { + LOG(DEBUG) << "getRadioCapability"; serial = GetRandomSerialNumber(); radio->getRadioCapability(serial); @@ -661,12 +733,14 @@ TEST_P(RadioHidlTest, getRadioCapability) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getRadioCapability finished"; } /* * Test IRadio.setRadioCapability() for the response returned. */ TEST_P(RadioHidlTest, setRadioCapability) { + LOG(DEBUG) << "setRadioCapability"; serial = GetRandomSerialNumber(); RadioCapability rc; memset(&rc, 0, sizeof(rc)); @@ -682,12 +756,14 @@ TEST_P(RadioHidlTest, setRadioCapability) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setRadioCapability finished"; } /* * Test IRadio.startLceService() for the response returned. */ TEST_P(RadioHidlTest, startLceService) { + LOG(DEBUG) << "startLceService"; serial = GetRandomSerialNumber(); radio->startLceService(serial, 5, true); @@ -701,12 +777,14 @@ TEST_P(RadioHidlTest, startLceService) { {RadioError::INTERNAL_ERR, RadioError::LCE_NOT_SUPPORTED, RadioError::RADIO_NOT_AVAILABLE, RadioError::SIM_ABSENT, RadioError::NONE})); } + LOG(DEBUG) << "startLceService finished"; } /* * Test IRadio.stopLceService() for the response returned. */ TEST_P(RadioHidlTest, stopLceService) { + LOG(DEBUG) << "stopLceService"; serial = GetRandomSerialNumber(); radio->stopLceService(serial); @@ -719,12 +797,14 @@ TEST_P(RadioHidlTest, stopLceService) { {RadioError::NONE, RadioError::LCE_NOT_SUPPORTED, RadioError::REQUEST_NOT_SUPPORTED, RadioError::SIM_ABSENT})); } + LOG(DEBUG) << "stopLceService finished"; } /* * Test IRadio.pullLceData() for the response returned. */ TEST_P(RadioHidlTest, pullLceData) { + LOG(DEBUG) << "pullLceData"; serial = GetRandomSerialNumber(); radio->pullLceData(serial); @@ -738,12 +818,14 @@ TEST_P(RadioHidlTest, pullLceData) { RadioError::RADIO_NOT_AVAILABLE, RadioError::SIM_ABSENT}, CHECK_OEM_ERROR)); } + LOG(DEBUG) << "pullLceData finished"; } /* * Test IRadio.getModemActivityInfo() for the response returned. */ TEST_P(RadioHidlTest, getModemActivityInfo) { + LOG(DEBUG) << "getModemActivityInfo"; serial = GetRandomSerialNumber(); radio->getModemActivityInfo(serial); @@ -755,6 +837,7 @@ TEST_P(RadioHidlTest, getModemActivityInfo) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "getModemActivityInfo finished"; } /* @@ -840,6 +923,7 @@ TEST_P(RadioHidlTest, DISABLED_setAllowedCarriers) { * Test IRadio.getAllowedCarriers() for the response returned. */ TEST_P(RadioHidlTest, getAllowedCarriers) { + LOG(DEBUG) << "getAllowedCarriers"; serial = GetRandomSerialNumber(); radio->getAllowedCarriers(serial); @@ -851,12 +935,14 @@ TEST_P(RadioHidlTest, getAllowedCarriers) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "getAllowedCarriers finished"; } /* * Test IRadio.sendDeviceState() for the response returned. */ TEST_P(RadioHidlTest, sendDeviceState) { + LOG(DEBUG) << "sendDeviceState"; serial = GetRandomSerialNumber(); radio->sendDeviceState(serial, DeviceStateType::POWER_SAVE_MODE, true); @@ -870,12 +956,14 @@ TEST_P(RadioHidlTest, sendDeviceState) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "sendDeviceState finished"; } /* * Test IRadio.setIndicationFilter() for the response returned. */ TEST_P(RadioHidlTest, setIndicationFilter) { + LOG(DEBUG) << "setIndicationFilter"; serial = GetRandomSerialNumber(); radio->setIndicationFilter(serial, 1); @@ -889,12 +977,14 @@ TEST_P(RadioHidlTest, setIndicationFilter) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "setIndicationFilter finished"; } /* * Test IRadio.setSimCardPower() for the response returned. */ TEST_P(RadioHidlTest, setSimCardPower) { + LOG(DEBUG) << "setSimCardPower"; serial = GetRandomSerialNumber(); radio->setSimCardPower(serial, true); @@ -906,4 +996,5 @@ TEST_P(RadioHidlTest, setSimCardPower) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED})); } + LOG(DEBUG) << "setSimCardPower finished"; } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp b/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp index 58c3bbd7de..0807deec2d 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include using namespace ::android::hardware::radio::V1_0; @@ -22,6 +23,7 @@ using namespace ::android::hardware::radio::V1_0; * Test IRadio.sendSms() for the response returned. */ TEST_P(RadioHidlTest, sendSms) { + LOG(DEBUG) << "sendSms"; serial = GetRandomSerialNumber(); GsmSmsMessage msg; msg.smscPdu = ""; @@ -40,12 +42,14 @@ TEST_P(RadioHidlTest, sendSms) { CHECK_GENERAL_ERROR)); EXPECT_EQ(0, radioRsp->sendSmsResult.errorCode); } + LOG(DEBUG) << "sendSms finished"; } /* * Test IRadio.sendSMSExpectMore() for the response returned. */ TEST_P(RadioHidlTest, sendSMSExpectMore) { + LOG(DEBUG) << "sendSMSExpectMore"; serial = GetRandomSerialNumber(); GsmSmsMessage msg; msg.smscPdu = ""; @@ -66,12 +70,14 @@ TEST_P(RadioHidlTest, sendSMSExpectMore) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendSMSExpectMore finished"; } /* * Test IRadio.acknowledgeLastIncomingGsmSms() for the response returned. */ TEST_P(RadioHidlTest, acknowledgeLastIncomingGsmSms) { + LOG(DEBUG) << "acknowledgeLastIncomingGsmSms"; serial = GetRandomSerialNumber(); bool success = true; @@ -87,12 +93,14 @@ TEST_P(RadioHidlTest, acknowledgeLastIncomingGsmSms) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "acknowledgeLastIncomingGsmSms finished"; } /* * Test IRadio.acknowledgeIncomingGsmSmsWithPdu() for the response returned. */ TEST_P(RadioHidlTest, acknowledgeIncomingGsmSmsWithPdu) { + LOG(DEBUG) << "acknowledgeIncomingGsmSmsWithPdu"; serial = GetRandomSerialNumber(); bool success = true; std::string ackPdu = ""; @@ -106,12 +114,14 @@ TEST_P(RadioHidlTest, acknowledgeIncomingGsmSmsWithPdu) { if (cardStatus.cardState == CardState::ABSENT) { // TODO(shuoq): Will add error check when we know the expected error from QC } + LOG(DEBUG) << "acknowledgeIncomingGsmSmsWithPdu finished"; } /* * Test IRadio.sendCdmaSms() for the response returned. */ TEST_P(RadioHidlTest, sendCdmaSms) { + LOG(DEBUG) << "sendCdmaSms"; serial = GetRandomSerialNumber(); // Create a CdmaSmsAddress @@ -150,12 +160,14 @@ TEST_P(RadioHidlTest, sendCdmaSms) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendCdmaSms finished"; } /* * Test IRadio.acknowledgeLastIncomingCdmaSms() for the response returned. */ TEST_P(RadioHidlTest, acknowledgeLastIncomingCdmaSms) { + LOG(DEBUG) << "acknowledgeLastIncomingCdmaSms"; serial = GetRandomSerialNumber(); // Create a CdmaSmsAck @@ -174,12 +186,14 @@ TEST_P(RadioHidlTest, acknowledgeLastIncomingCdmaSms) { {RadioError::INVALID_ARGUMENTS, RadioError::NO_SMS_TO_ACK}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "acknowledgeLastIncomingCdmaSms finished"; } /* * Test IRadio.sendImsSms() for the response returned. */ TEST_P(RadioHidlTest, sendImsSms) { + LOG(DEBUG) << "sendImsSms"; serial = GetRandomSerialNumber(); // Create a CdmaSmsAddress @@ -224,12 +238,14 @@ TEST_P(RadioHidlTest, sendImsSms) { ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::INVALID_ARGUMENTS}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendImsSms finished"; } /* * Test IRadio.getSmscAddress() for the response returned. */ TEST_P(RadioHidlTest, getSmscAddress) { + LOG(DEBUG) << "getSmscAddress"; serial = GetRandomSerialNumber(); radio->getSmscAddress(serial); @@ -244,12 +260,14 @@ TEST_P(RadioHidlTest, getSmscAddress) { {RadioError::INVALID_MODEM_STATE, RadioError::INVALID_STATE, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getSmscAddress finished"; } /* * Test IRadio.setSmscAddress() for the response returned. */ TEST_P(RadioHidlTest, setSmscAddress) { + LOG(DEBUG) << "setSmscAddress"; serial = GetRandomSerialNumber(); hidl_string address = hidl_string("smscAddress"); @@ -265,12 +283,14 @@ TEST_P(RadioHidlTest, setSmscAddress) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_SMS_FORMAT, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setSmscAddress finished"; } /* * Test IRadio.writeSmsToSim() for the response returned. */ TEST_P(RadioHidlTest, writeSmsToSim) { + LOG(DEBUG) << "writeSmsToSim"; serial = GetRandomSerialNumber(); SmsWriteArgs smsWriteArgs; smsWriteArgs.status = SmsWriteArgsStatus::REC_UNREAD; @@ -291,12 +311,14 @@ TEST_P(RadioHidlTest, writeSmsToSim) { RadioError::NO_RESOURCES, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "writeSmsToSim finished"; } /* * Test IRadio.deleteSmsOnSim() for the response returned. */ TEST_P(RadioHidlTest, deleteSmsOnSim) { + LOG(DEBUG) << "deleteSmsOnSim"; serial = GetRandomSerialNumber(); int index = 1; @@ -314,12 +336,14 @@ TEST_P(RadioHidlTest, deleteSmsOnSim) { RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "deleteSmsOnSim finished"; } /* * Test IRadio.writeSmsToRuim() for the response returned. */ TEST_P(RadioHidlTest, writeSmsToRuim) { + LOG(DEBUG) << "writeSmsToRuim"; serial = GetRandomSerialNumber(); // Create a CdmaSmsAddress @@ -365,12 +389,14 @@ TEST_P(RadioHidlTest, writeSmsToRuim) { RadioError::NO_SUCH_ENTRY, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "writeSmsToRuim finished"; } /* * Test IRadio.deleteSmsOnRuim() for the response returned. */ TEST_P(RadioHidlTest, deleteSmsOnRuim) { + LOG(DEBUG) << "deleteSmsOnRuim"; serial = GetRandomSerialNumber(); int index = 1; @@ -416,12 +442,14 @@ TEST_P(RadioHidlTest, deleteSmsOnRuim) { RadioError::MODEM_ERR, RadioError::NO_SUCH_ENTRY, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "deleteSmsOnRuim finished"; } /* * Test IRadio.reportSmsMemoryStatus() for the response returned. */ TEST_P(RadioHidlTest, reportSmsMemoryStatus) { + LOG(DEBUG) << "reportSmsMemoryStatus"; serial = GetRandomSerialNumber(); bool available = true; @@ -437,4 +465,5 @@ TEST_P(RadioHidlTest, reportSmsMemoryStatus) { RadioError::MODEM_ERR, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "reportSmsMemoryStatus finished"; } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp b/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp index 1170111fba..193c25dcc0 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include using namespace ::android::hardware::radio::V1_0; @@ -22,6 +23,7 @@ using namespace ::android::hardware::radio::V1_0; * Test IRadio.sendEnvelope() for the response returned. */ TEST_P(RadioHidlTest, sendEnvelope) { + LOG(DEBUG) << "sendEnvelope"; serial = GetRandomSerialNumber(); // Test with sending empty string @@ -39,12 +41,14 @@ TEST_P(RadioHidlTest, sendEnvelope) { RadioError::MODEM_ERR, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendEnvelope finished"; } /* * Test IRadio.sendTerminalResponseToSim() for the response returned. */ TEST_P(RadioHidlTest, sendTerminalResponseToSim) { + LOG(DEBUG) << "sendTerminalResponseToSim"; serial = GetRandomSerialNumber(); // Test with sending empty string @@ -62,12 +66,14 @@ TEST_P(RadioHidlTest, sendTerminalResponseToSim) { {RadioError::NONE, RadioError::INVALID_ARGUMENTS, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendTerminalResponseToSim finished"; } /* * Test IRadio.handleStkCallSetupRequestFromSim() for the response returned. */ TEST_P(RadioHidlTest, handleStkCallSetupRequestFromSim) { + LOG(DEBUG) << "handleStkCallSetupRequestFromSim"; serial = GetRandomSerialNumber(); bool accept = false; @@ -83,12 +89,14 @@ TEST_P(RadioHidlTest, handleStkCallSetupRequestFromSim) { RadioError::MODEM_ERR, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "handleStkCallSetupRequestFromSim finished"; } /* * Test IRadio.reportStkServiceIsRunning() for the response returned. */ TEST_P(RadioHidlTest, reportStkServiceIsRunning) { + LOG(DEBUG) << "reportStkServiceIsRunning"; serial = GetRandomSerialNumber(); radio->reportStkServiceIsRunning(serial); @@ -101,6 +109,7 @@ TEST_P(RadioHidlTest, reportStkServiceIsRunning) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "reportStkServiceIsRunning finished"; } /* @@ -108,6 +117,7 @@ TEST_P(RadioHidlTest, reportStkServiceIsRunning) { * string. */ TEST_P(RadioHidlTest, sendEnvelopeWithStatus) { + LOG(DEBUG) << "sendEnvelopeWithStatus"; serial = GetRandomSerialNumber(); // Test with sending empty string @@ -125,4 +135,5 @@ TEST_P(RadioHidlTest, sendEnvelopeWithStatus) { {RadioError::INVALID_ARGUMENTS, RadioError::MODEM_ERR, RadioError::SIM_ABSENT}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendEnvelopeWithStatus finished"; } diff --git a/radio/1.0/vts/functional/radio_hidl_hal_test.cpp b/radio/1.0/vts/functional/radio_hidl_hal_test.cpp index 3c833c0c20..3583514014 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_test.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_test.cpp @@ -14,11 +14,13 @@ * limitations under the License. */ +#include #include void RadioHidlTest::SetUp() { radio = IRadio::getService(GetParam()); if (radio == NULL) { + LOG(DEBUG) << "Radio is NULL, waiting 1 minute to retry"; sleep(60); radio = IRadio::getService(GetParam()); } @@ -70,4 +72,4 @@ void RadioHidlTest::updateSimCardStatus() { serial = GetRandomSerialNumber(); radio->getIccCardStatus(serial); EXPECT_EQ(std::cv_status::no_timeout, wait()); -} \ No newline at end of file +} diff --git a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp index a192a33a07..f6de2f854a 100644 --- a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp +++ b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp @@ -14,12 +14,14 @@ * limitations under the License. */ +#include #include /* * Test IRadio.getCurrentCalls() for the response returned. */ TEST_P(RadioHidlTest, getCurrentCalls) { + LOG(DEBUG) << "getCurrentCalls"; serial = GetRandomSerialNumber(); radio->getCurrentCalls(serial); @@ -30,12 +32,14 @@ TEST_P(RadioHidlTest, getCurrentCalls) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getCurrentCalls finished"; } /* * Test IRadio.dial() for the response returned. */ TEST_P(RadioHidlTest, dial) { + LOG(DEBUG) << "dial"; serial = GetRandomSerialNumber(); Dial dialInfo; @@ -57,12 +61,14 @@ TEST_P(RadioHidlTest, dial) { RadioError::OPERATION_NOT_ALLOWED}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "dial finished"; } /* * Test IRadio.hangup() for the response returned. */ TEST_P(RadioHidlTest, hangup) { + LOG(DEBUG) << "hangup"; serial = GetRandomSerialNumber(); radio->hangup(serial, 1); @@ -76,12 +82,14 @@ TEST_P(RadioHidlTest, hangup) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "hangup finished"; } /* * Test IRadio.hangupWaitingOrBackground() for the response returned. */ TEST_P(RadioHidlTest, hangupWaitingOrBackground) { + LOG(DEBUG) << "hangupWaitingOrBackground"; serial = GetRandomSerialNumber(); radio->hangupWaitingOrBackground(serial); @@ -94,12 +102,14 @@ TEST_P(RadioHidlTest, hangupWaitingOrBackground) { {RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "hangupWaitingOrBackground finished"; } /* * Test IRadio.hangupForegroundResumeBackground() for the response returned. */ TEST_P(RadioHidlTest, hangupForegroundResumeBackground) { + LOG(DEBUG) << "hangupForegroundResumeBackground"; serial = GetRandomSerialNumber(); radio->hangupForegroundResumeBackground(serial); @@ -112,12 +122,14 @@ TEST_P(RadioHidlTest, hangupForegroundResumeBackground) { {RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "hangupForegroundResumeBackground finished"; } /* * Test IRadio.switchWaitingOrHoldingAndActive() for the response returned. */ TEST_P(RadioHidlTest, switchWaitingOrHoldingAndActive) { + LOG(DEBUG) << "switchWaitingOrHoldingAndActive"; serial = GetRandomSerialNumber(); radio->switchWaitingOrHoldingAndActive(serial); @@ -130,12 +142,14 @@ TEST_P(RadioHidlTest, switchWaitingOrHoldingAndActive) { {RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "switchWaitingOrHoldingAndActive finished"; } /* * Test IRadio.conference() for the response returned. */ TEST_P(RadioHidlTest, conference) { + LOG(DEBUG) << "conference"; serial = GetRandomSerialNumber(); radio->conference(serial); @@ -148,12 +162,14 @@ TEST_P(RadioHidlTest, conference) { {RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "conference finished"; } /* * Test IRadio.rejectCall() for the response returned. */ TEST_P(RadioHidlTest, rejectCall) { + LOG(DEBUG) << "rejectCall"; serial = GetRandomSerialNumber(); radio->rejectCall(serial); @@ -166,12 +182,14 @@ TEST_P(RadioHidlTest, rejectCall) { {RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "rejectCall finished"; } /* * Test IRadio.getLastCallFailCause() for the response returned. */ TEST_P(RadioHidlTest, getLastCallFailCause) { + LOG(DEBUG) << "getLastCallFailCause"; serial = GetRandomSerialNumber(); radio->getLastCallFailCause(serial); @@ -183,12 +201,14 @@ TEST_P(RadioHidlTest, getLastCallFailCause) { ASSERT_TRUE( CheckAnyOfErrors(radioRsp->rspInfo.error, {RadioError::NONE}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getLastCallFailCause finished"; } /* * Test IRadio.sendUssd() for the response returned. */ TEST_P(RadioHidlTest, sendUssd) { + LOG(DEBUG) << "sendUssd"; serial = GetRandomSerialNumber(); radio->sendUssd(serial, hidl_string("test")); EXPECT_EQ(std::cv_status::no_timeout, wait()); @@ -201,12 +221,14 @@ TEST_P(RadioHidlTest, sendUssd) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendUssd finished"; } /* * Test IRadio.cancelPendingUssd() for the response returned. */ TEST_P(RadioHidlTest, cancelPendingUssd) { + LOG(DEBUG) << "cancelPendingUssd"; serial = GetRandomSerialNumber(); radio->cancelPendingUssd(serial); @@ -220,12 +242,14 @@ TEST_P(RadioHidlTest, cancelPendingUssd) { {RadioError::NONE, RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "cancelPendingUssd finished"; } /* * Test IRadio.getCallForwardStatus() for the response returned. */ TEST_P(RadioHidlTest, getCallForwardStatus) { + LOG(DEBUG) << "getCallForwardStatus"; serial = GetRandomSerialNumber(); CallForwardInfo callInfo; memset(&callInfo, 0, sizeof(callInfo)); @@ -242,12 +266,14 @@ TEST_P(RadioHidlTest, getCallForwardStatus) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getCallForwardStatus finished"; } /* * Test IRadio.setCallForward() for the response returned. */ TEST_P(RadioHidlTest, setCallForward) { + LOG(DEBUG) << "setCallForward"; serial = GetRandomSerialNumber(); CallForwardInfo callInfo; memset(&callInfo, 0, sizeof(callInfo)); @@ -264,12 +290,14 @@ TEST_P(RadioHidlTest, setCallForward) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setCallForward finished"; } /* * Test IRadio.getCallWaiting() for the response returned. */ TEST_P(RadioHidlTest, getCallWaiting) { + LOG(DEBUG) << "getCallWaiting"; serial = GetRandomSerialNumber(); radio->getCallWaiting(serial, 1); @@ -283,12 +311,14 @@ TEST_P(RadioHidlTest, getCallWaiting) { {RadioError::NONE, RadioError::INVALID_ARGUMENTS, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "getCallWaiting finished"; } /* * Test IRadio.setCallWaiting() for the response returned. */ TEST_P(RadioHidlTest, setCallWaiting) { + LOG(DEBUG) << "setCallWaiting"; serial = GetRandomSerialNumber(); radio->setCallWaiting(serial, true, 1); @@ -302,12 +332,14 @@ TEST_P(RadioHidlTest, setCallWaiting) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setCallWaiting finished"; } /* * Test IRadio.acceptCall() for the response returned. */ TEST_P(RadioHidlTest, acceptCall) { + LOG(DEBUG) << "acceptCall"; serial = GetRandomSerialNumber(); radio->acceptCall(serial); @@ -320,12 +352,14 @@ TEST_P(RadioHidlTest, acceptCall) { {RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "acceptCall finished"; } /* * Test IRadio.separateConnection() for the response returned. */ TEST_P(RadioHidlTest, separateConnection) { + LOG(DEBUG) << "separateConnection"; serial = GetRandomSerialNumber(); radio->separateConnection(serial, 1); @@ -339,12 +373,14 @@ TEST_P(RadioHidlTest, separateConnection) { {RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "separateConnection finished"; } /* * Test IRadio.explicitCallTransfer() for the response returned. */ TEST_P(RadioHidlTest, explicitCallTransfer) { + LOG(DEBUG) << "explicitCallTransfer"; serial = GetRandomSerialNumber(); radio->explicitCallTransfer(serial); @@ -357,12 +393,14 @@ TEST_P(RadioHidlTest, explicitCallTransfer) { {RadioError::INVALID_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "explicitCallTransfer finished"; } /* * Test IRadio.sendCDMAFeatureCode() for the response returned. */ TEST_P(RadioHidlTest, sendCDMAFeatureCode) { + LOG(DEBUG) << "sendCDMAFeatureCode"; serial = GetRandomSerialNumber(); radio->sendCDMAFeatureCode(serial, hidl_string()); @@ -377,12 +415,14 @@ TEST_P(RadioHidlTest, sendCDMAFeatureCode) { RadioError::MODEM_ERR, RadioError::OPERATION_NOT_ALLOWED}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendCDMAFeatureCode finished"; } /* * Test IRadio.sendDtmf() for the response returned. */ TEST_P(RadioHidlTest, sendDtmf) { + LOG(DEBUG) << "sendDtmf"; serial = GetRandomSerialNumber(); radio->sendDtmf(serial, "1"); @@ -397,12 +437,14 @@ TEST_P(RadioHidlTest, sendDtmf) { RadioError::INVALID_MODEM_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendDtmf finished"; } /* * Test IRadio.startDtmf() for the response returned. */ TEST_P(RadioHidlTest, startDtmf) { + LOG(DEBUG) << "startDtmf"; serial = GetRandomSerialNumber(); radio->startDtmf(serial, "1"); @@ -417,12 +459,14 @@ TEST_P(RadioHidlTest, startDtmf) { RadioError::INVALID_MODEM_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "startDtmf finished"; } /* * Test IRadio.stopDtmf() for the response returned. */ TEST_P(RadioHidlTest, stopDtmf) { + LOG(DEBUG) << "stopDtmf"; serial = GetRandomSerialNumber(); radio->stopDtmf(serial); @@ -436,12 +480,14 @@ TEST_P(RadioHidlTest, stopDtmf) { RadioError::INVALID_MODEM_STATE, RadioError::MODEM_ERR}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "stopDtmf finished"; } /* * Test IRadio.setMute() for the response returned. */ TEST_P(RadioHidlTest, setMute) { + LOG(DEBUG) << "setMute"; serial = GetRandomSerialNumber(); radio->setMute(serial, true); @@ -454,12 +500,14 @@ TEST_P(RadioHidlTest, setMute) { {RadioError::NONE, RadioError::INVALID_ARGUMENTS}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "setMute finished"; } /* * Test IRadio.getMute() for the response returned. */ TEST_P(RadioHidlTest, getMute) { + LOG(DEBUG) << "getMute"; serial = GetRandomSerialNumber(); radio->getMute(serial); @@ -470,12 +518,14 @@ TEST_P(RadioHidlTest, getMute) { if (cardStatus.cardState == CardState::ABSENT) { EXPECT_EQ(RadioError::NONE, radioRsp->rspInfo.error); } + LOG(DEBUG) << "getMute finished"; } /* * Test IRadio.sendBurstDtmf() for the response returned. */ TEST_P(RadioHidlTest, sendBurstDtmf) { + LOG(DEBUG) << "sendBurstDtmf"; serial = GetRandomSerialNumber(); radio->sendBurstDtmf(serial, "1", 0, 0); @@ -489,4 +539,5 @@ TEST_P(RadioHidlTest, sendBurstDtmf) { RadioError::MODEM_ERR, RadioError::OPERATION_NOT_ALLOWED}, CHECK_GENERAL_ERROR)); } + LOG(DEBUG) << "sendBurstDtmf finished"; } diff --git a/radio/1.0/vts/functional/sap_hidl_hal_api.cpp b/radio/1.0/vts/functional/sap_hidl_hal_api.cpp index 6bd2c88a05..6c7870d399 100644 --- a/radio/1.0/vts/functional/sap_hidl_hal_api.cpp +++ b/radio/1.0/vts/functional/sap_hidl_hal_api.cpp @@ -14,12 +14,14 @@ * limitations under the License. */ +#include #include /* * Test ISap.connectReq() for the response returned. */ TEST_P(SapHidlTest, connectReq) { + LOG(DEBUG) << "connectReq"; token = GetRandomSerialNumber(); int32_t maxMsgSize = 100; @@ -30,23 +32,27 @@ TEST_P(SapHidlTest, connectReq) { // Modem side need time for connect to finish. Adding a waiting time to prevent // disconnect being requested right after connect request. sleep(1); + LOG(DEBUG) << "connectReq finished"; } /* * Test IRadio.disconnectReq() for the response returned */ TEST_P(SapHidlTest, disconnectReq) { + LOG(DEBUG) << "disconnectReq"; token = GetRandomSerialNumber(); sap->disconnectReq(token); EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(sapCb->sapResponseToken, token); + LOG(DEBUG) << "disconnectReq finished"; } /* * Test IRadio.apduReq() for the response returned. */ TEST_P(SapHidlTest, apduReq) { + LOG(DEBUG) << "apduReq"; token = GetRandomSerialNumber(); SapApduType sapApduType = SapApduType::APDU; android::hardware::hidl_vec command = {}; @@ -59,12 +65,14 @@ TEST_P(SapHidlTest, apduReq) { CheckAnyOfErrors(sapCb->sapResultCode, {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_NOT_ACCESSSIBLE, SapResultCode::CARD_REMOVED})); + LOG(DEBUG) << "apduReq finished"; } /* * Test IRadio.transferAtrReq() for the response returned. */ TEST_P(SapHidlTest, transferAtrReq) { + LOG(DEBUG) << "transferAtrReq"; token = GetRandomSerialNumber(); sap->transferAtrReq(token); @@ -75,12 +83,14 @@ TEST_P(SapHidlTest, transferAtrReq) { CheckAnyOfErrors(sapCb->sapResultCode, {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE, SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED})); + LOG(DEBUG) << "transferAtrReq finished"; } /* * Test IRadio.powerReq() for the response returned. */ TEST_P(SapHidlTest, powerReq) { + LOG(DEBUG) << "powerReq"; token = GetRandomSerialNumber(); bool state = true; @@ -92,12 +102,14 @@ TEST_P(SapHidlTest, powerReq) { sapCb->sapResultCode, {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE, SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED, SapResultCode::CARD_ALREADY_POWERED_ON})); + LOG(DEBUG) << "powerReq finished"; } /* * Test IRadio.resetSimReq() for the response returned. */ TEST_P(SapHidlTest, resetSimReq) { + LOG(DEBUG) << "resetSimReq"; token = GetRandomSerialNumber(); sap->resetSimReq(token); @@ -108,12 +120,14 @@ TEST_P(SapHidlTest, resetSimReq) { CheckAnyOfErrors(sapCb->sapResultCode, {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE, SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED})); + LOG(DEBUG) << "resetSimReq finished"; } /* * Test IRadio.transferCardReaderStatusReq() for the response returned. */ TEST_P(SapHidlTest, transferCardReaderStatusReq) { + LOG(DEBUG) << "transferCardReaderStatusReq"; token = GetRandomSerialNumber(); sap->transferCardReaderStatusReq(token); @@ -122,12 +136,14 @@ TEST_P(SapHidlTest, transferCardReaderStatusReq) { ASSERT_TRUE(CheckAnyOfErrors( sapCb->sapResultCode, {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE})); + LOG(DEBUG) << "transferCardReaderStatusReq finished"; } /* * Test IRadio.setTransferProtocolReq() for the response returned. */ TEST_P(SapHidlTest, setTransferProtocolReq) { + LOG(DEBUG) << "setTransferProtocolReq"; token = GetRandomSerialNumber(); SapTransferProtocol sapTransferProtocol = SapTransferProtocol::T0; @@ -136,4 +152,5 @@ TEST_P(SapHidlTest, setTransferProtocolReq) { EXPECT_EQ(sapCb->sapResponseToken, token); EXPECT_EQ(SapResultCode::NOT_SUPPORTED, sapCb->sapResultCode); + LOG(DEBUG) << "setTransferProtocolReq finished"; } diff --git a/radio/1.0/vts/functional/vts_hal_radio_target_test.xml b/radio/1.0/vts/functional/vts_hal_radio_target_test.xml index b91119d40a..82af2ee388 100644 --- a/radio/1.0/vts/functional/vts_hal_radio_target_test.xml +++ b/radio/1.0/vts/functional/vts_hal_radio_target_test.xml @@ -30,5 +30,6 @@ diff --git a/radio/1.0/vts/functional/vts_hal_sap_target_test.xml b/radio/1.0/vts/functional/vts_hal_sap_target_test.xml index 876e1fba12..d7d44773c4 100644 --- a/radio/1.0/vts/functional/vts_hal_sap_target_test.xml +++ b/radio/1.0/vts/functional/vts_hal_sap_target_test.xml @@ -22,6 +22,8 @@ + +